diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/transaction/Neo4jResourceHolder.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/transaction/Neo4jResourceHolder.java index 73b99b3a1..f49a0925a 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/transaction/Neo4jResourceHolder.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/transaction/Neo4jResourceHolder.java @@ -38,11 +38,11 @@ public class Neo4jResourceHolder extends ResourceHolderSupport { private final Transaction transaction; - public Neo4jResourceHolder(Session session) { + Neo4jResourceHolder(Session session) { this(session, TransactionConfig.empty()); } - public Neo4jResourceHolder(Session session, TransactionConfig transactionConfig) { + Neo4jResourceHolder(Session session, TransactionConfig transactionConfig) { this.session = session; this.transaction = this.session.beginTransaction(transactionConfig); @@ -52,7 +52,7 @@ public class Neo4jResourceHolder extends ResourceHolderSupport { return transaction; } - public void commit() { + void commit() { Assert.state(hasActiveTransaction(), "Transaction must be open, but has already been closed."); Assert.state(!isRollbackOnly(), "Resource msut not be marked as rollback only."); @@ -61,7 +61,7 @@ public class Neo4jResourceHolder extends ResourceHolderSupport { transaction.close(); } - public void rollback() { + void rollback() { Assert.state(hasActiveTransaction(), "Transaction must be open, but has already been closed."); @@ -69,7 +69,7 @@ public class Neo4jResourceHolder extends ResourceHolderSupport { transaction.close(); } - public void close() { + void close() { Assert.state(hasActiveSession(), "Session must be open, but has already been closed."); @@ -90,12 +90,12 @@ public class Neo4jResourceHolder extends ResourceHolderSupport { throw new UnsupportedOperationException(); } - public boolean hasActiveSession() { + boolean hasActiveSession() { return session.isOpen(); } - public boolean hasActiveTransaction() { + boolean hasActiveTransaction() { return transaction.isOpen(); } diff --git a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/transaction/Neo4jTransactionManager.java b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/transaction/Neo4jTransactionManager.java index f956b7153..486d40d79 100644 --- a/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/transaction/Neo4jTransactionManager.java +++ b/spring-data-neo4j/src/main/java/org/springframework/data/neo4j/core/transaction/Neo4jTransactionManager.java @@ -89,8 +89,7 @@ public class Neo4jTransactionManager extends AbstractPlatformTransactionManager resourceHolder.setSynchronizedWithTransaction(true); TransactionSynchronizationManager.bindResource(driver, resourceHolder); } catch (Exception ex) { - ex.printStackTrace(); - throw new TransactionSystemException(String.format("Could not open a new Neo4j session:", ex)); + throw new TransactionSystemException(String.format("Could not open a new Neo4j session: %s", ex.getMessage())); } } diff --git a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/core/transaction/DefaultNeo4jStatementRunnerSupplierTest.java b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/core/transaction/DefaultNeo4jStatementRunnerSupplierTest.java index 7efe3a9e9..3a6266f50 100644 --- a/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/core/transaction/DefaultNeo4jStatementRunnerSupplierTest.java +++ b/spring-data-neo4j/src/test/java/org/springframework/data/neo4j/core/transaction/DefaultNeo4jStatementRunnerSupplierTest.java @@ -35,6 +35,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; import org.neo4j.driver.v1.AccessMode; import org.neo4j.driver.v1.Driver; import org.neo4j.driver.v1.Session; @@ -51,6 +53,7 @@ import org.springframework.transaction.support.TransactionTemplate; * @author Michael J. Simons */ @ExtendWith(MockitoExtension.class) +@MockitoSettings(strictness = Strictness.LENIENT) class DefaultNeo4jStatementRunnerSupplierTest { @Mock @@ -68,6 +71,7 @@ class DefaultNeo4jStatementRunnerSupplierTest { AtomicBoolean sessionIsOpen = new AtomicBoolean(true); AtomicBoolean transactionIsOpen = new AtomicBoolean(true); + when(driver.session()).thenReturn(session); when(driver.session(AccessMode.WRITE, Collections.emptyList())).thenReturn(session); when(session.beginTransaction(any(TransactionConfig.class))).thenReturn(transaction); @@ -84,6 +88,100 @@ class DefaultNeo4jStatementRunnerSupplierTest { when(transaction.isOpen()).thenAnswer(invocation -> transactionIsOpen.get()); } + @Test + void shouldWorkWithoutSynchronizations() { + StatementRunnerSupplier statementRunnerSupplier = new DefaultNeo4jStatementRunnerSupplier( + driver); + + @SuppressWarnings({ "unused" }) + StatementRunner statementRunner = statementRunnerSupplier.get(); + + verify(driver).session(); + verifyNoMoreInteractions(driver, session, transaction); + } + + @Nested + class BasedOnNeo4jTransactions { + @Test + void shouldOpenNewTransaction() { + + Neo4jTransactionManager txManager = new Neo4jTransactionManager(driver); + TransactionTemplate txTemplate = new TransactionTemplate(txManager); + StatementRunnerSupplier statementRunnerSupplier = new DefaultNeo4jStatementRunnerSupplier( + driver); + + txTemplate.execute(new TransactionCallbackWithoutResult() { + + @Override + protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { + + assertThat(TransactionSynchronizationManager.isSynchronizationActive()).isTrue(); + assertThat(transactionStatus.isNewTransaction()).isTrue(); + assertThat(TransactionSynchronizationManager.hasResource(driver)).isTrue(); + + @SuppressWarnings({ "unused" }) + StatementRunner statementRunner = statementRunnerSupplier.get(); + + transactionStatus.setRollbackOnly(); + } + }); + + verify(driver).session(AccessMode.WRITE, Collections.emptyList()); + + verify(session).isOpen(); + verify(session).beginTransaction(any(TransactionConfig.class)); + verify(session).close(); + + verify(transaction, times(2)).isOpen(); + verify(transaction).failure(); + verify(transaction).close(); + } + + @Test + void shouldParticipateInOngoingTransaction() { + + Neo4jTransactionManager txManager = new Neo4jTransactionManager(driver); + TransactionTemplate txTemplate = new TransactionTemplate(txManager); + StatementRunnerSupplier statementRunnerSupplier = new DefaultNeo4jStatementRunnerSupplier( + driver); + + txTemplate.execute(new TransactionCallbackWithoutResult() { + + @Override + protected void doInTransactionWithoutResult(TransactionStatus outerStatus) { + + @SuppressWarnings({ "unused" }) + StatementRunner outerStatementRunner = statementRunnerSupplier.get(); + assertThat(outerStatus.isNewTransaction()).isTrue(); + + txTemplate.execute(new TransactionCallbackWithoutResult() { + + @Override + protected void doInTransactionWithoutResult(TransactionStatus innerStatus) { + + assertThat(innerStatus.isNewTransaction()).isFalse(); + + @SuppressWarnings({ "unused" }) + StatementRunner innerStatementRunner = statementRunnerSupplier.get(); + } + }); + + outerStatus.setRollbackOnly(); + } + }); + + verify(driver).session(AccessMode.WRITE, Collections.emptyList()); + + verify(session).isOpen(); + verify(session).beginTransaction(any(TransactionConfig.class)); + verify(session).close(); + + verify(transaction, times(2)).isOpen(); + verify(transaction).failure(); + verify(transaction).close(); + } + } + @Nested class BasedOnJtaTransactions { @@ -107,6 +205,7 @@ class DefaultNeo4jStatementRunnerSupplierTest { assertThat(transactionStatus.isNewTransaction()).isTrue(); assertThat(TransactionSynchronizationManager.hasResource(driver)).isFalse(); + @SuppressWarnings({ "unused" }) StatementRunner statementRunner = statementRunnerSupplier.get(); assertThat(TransactionSynchronizationManager.hasResource(driver)).isTrue(); @@ -127,7 +226,7 @@ class DefaultNeo4jStatementRunnerSupplierTest { } @Test - public void shouldParticipateInOngoingTransactionWithRollback() throws Exception { + void shouldParticipateInOngoingTransactionWithRollback() throws Exception { when(userTransaction.getStatus()).thenReturn(Status.STATUS_NO_TRANSACTION, Status.STATUS_ACTIVE, Status.STATUS_ACTIVE); @@ -170,44 +269,6 @@ class DefaultNeo4jStatementRunnerSupplierTest { } } - @Nested - class BasedOnNeo4jTransactions { - @Test - public void shouldParticipateInOngoingTransaction() { - - Neo4jTransactionManager txManager = new Neo4jTransactionManager(driver); - TransactionTemplate txTemplate = new TransactionTemplate(txManager); - StatementRunnerSupplier statementRunnerSupplier = new DefaultNeo4jStatementRunnerSupplier( - driver); - - txTemplate.execute(new TransactionCallbackWithoutResult() { - - @Override - protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { - - assertThat(TransactionSynchronizationManager.isSynchronizationActive()).isTrue(); - assertThat(transactionStatus.isNewTransaction()).isTrue(); - assertThat(TransactionSynchronizationManager.hasResource(driver)).isTrue(); - - @SuppressWarnings({ "unused" }) - StatementRunner statementRunner = statementRunnerSupplier.get(); - - transactionStatus.setRollbackOnly(); - } - }); - - verify(driver).session(AccessMode.WRITE, Collections.emptyList()); - - verify(session).isOpen(); - verify(session).beginTransaction(any(TransactionConfig.class)); - verify(session).close(); - - verify(transaction, times(2)).isOpen(); - verify(transaction).failure(); - verify(transaction).close(); - } - } - @AfterEach void verifyTransactionSynchronizationManagerState() {