/*
* Hibernate OGM, Domain model persistence for NoSQL datastores
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.ogm.datastore.neo4j.test.transaction;
import static org.fest.assertions.Assertions.assertThat;
import static org.hibernate.ogm.datastore.neo4j.dialect.impl.NodeLabel.ENTITY;
import static org.hibernate.ogm.datastore.neo4j.test.dsl.GraphAssertions.node;
import static org.junit.Assert.fail;
import javax.persistence.EntityManager;
import javax.persistence.spi.PersistenceUnitTransactionType;
import javax.transaction.Synchronization;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import org.hibernate.ogm.datastore.neo4j.test.dsl.NodeForGraphAssertions;
import org.hibernate.ogm.datastore.neo4j.test.mapping.Neo4jJpaTestCase;
import org.hibernate.ogm.utils.jpa.GetterPersistenceUnitInfo;
import org.junit.Test;
/**
* Test for using the compensation SPI with JPA.
*
* @author Gunnar Morling
*/
public class JtaRollbackTest extends Neo4jJpaTestCase {
@Override
protected void configure(GetterPersistenceUnitInfo info) {
info.setTransactionType( PersistenceUnitTransactionType.JTA );
}
@Test
public void testRollbackCausedByException() throws Exception {
final Game game1 = new Game( "game-1", "Title 1" );
TransactionManager transactionManager = getTransactionManager( getFactory() );
transactionManager.begin();
EntityManager em = getFactory().createEntityManager();
em.persist( game1 );
em.flush();
em.clear();
transactionManager.commit();
transactionManager.begin();
em.joinTransaction();
try {
// This should generate an exception because we already have an entry with the same id in the db
em.persist( new Game( game1.getId(), "New " + game1.getTitle() ) );
transactionManager.commit();
fail( "Expected exception was not raised" );
}
catch (Exception e) {
// Entity already exists exception
assertThat( e.getCause().getMessage() ).matches( ".*OGM000067.*" );
}
em.close();
NodeForGraphAssertions gameNode1 = node( "g1", Game.class.getSimpleName(), ENTITY.name() )
.property( "id", game1.getId() )
.property( "title", game1.getTitle() );
assertThatOnlyTheseNodesExist( gameNode1 );
}
@Test
public void testManualRollback() throws Exception {
final Game game1 = new Game( "game-1", "Title 1" );
TransactionManager transactionManager = getTransactionManager( getFactory() );
transactionManager.begin();
EntityManager em = getFactory().createEntityManager();
em.persist( game1 );
em.flush();
em.clear();
transactionManager.commit();
transactionManager.begin();
em.joinTransaction();
em.persist( new Game( "game-2", "Title 2" ) );
transactionManager.rollback();
em.close();
NodeForGraphAssertions gameNode1 = node( "g1", Game.class.getSimpleName(), ENTITY.name() )
.property( "id", game1.getId() )
.property( "title", game1.getTitle() );
assertThatOnlyTheseNodesExist( gameNode1 );
}
@Test
// Neo4j is not an XAResource, and it will commit before the JTA transaction is committed.
// If something goes wrong after the Neo4j transaction has been closed, it won't be possible to rollback.
//
// Note that this test might fails for two reasons:
// 1) Neo4j participate correctly to the JTA transaction
// 2) The failure occurs before Neo4j has synchronized
//
// If one of these situations occurs you will need to udpate the test
public void testFailedRollback() throws Exception {
final Game game1 = new Game( "game-1", "Title 1" );
final Game game2 = new Game( "game-2", "Title 2" );
TransactionManager transactionManager = getTransactionManager( getFactory() );
transactionManager.begin();
EntityManager em = getFactory().createEntityManager();
em.persist( game1 );
em.flush();
em.clear();
transactionManager.commit();
transactionManager.begin();
em.joinTransaction();
Transaction transaction = transactionManager.getTransaction();
transaction.registerSynchronization( new Synchronization() {
@Override
public void beforeCompletion() {
throw new RuntimeException( "Don't panic; this is just a test" );
}
@Override
public void afterCompletion(int status) {
}
} );
em.persist( game2 );
try {
transactionManager.commit();
fail( "Expected exception was not raised" );
}
catch (Exception e) {
// Exception raise by a registered synchronisation
assertThat( e.getCause().getMessage() ).matches( ".*Don't panic.*" );
}
em.close();
NodeForGraphAssertions gameNode1 = node( "g1", Game.class.getSimpleName(), ENTITY.name() )
.property( "id", game1.getId() )
.property( "title", game1.getTitle() );
NodeForGraphAssertions gameNode2 = node( "g2", Game.class.getSimpleName(), ENTITY.name() )
.property( "id", game2.getId() )
.property( "title", game2.getTitle() );
assertThatOnlyTheseNodesExist( gameNode1, gameNode2 );
}
@Override
public Class<?>[] getAnnotatedClasses() {
return new Class<?>[] { Game.class };
}
}