|
29 | 29 | import static org.junit.jupiter.api.Assertions.assertTrue;
|
30 | 30 | import static org.mockito.ArgumentMatchers.any;
|
31 | 31 | import static org.mockito.ArgumentMatchers.argThat;
|
| 32 | +import static org.mockito.ArgumentMatchers.eq; |
32 | 33 | import static org.mockito.BDDMockito.given;
|
33 | 34 | import static org.mockito.BDDMockito.then;
|
34 | 35 | import static org.mockito.Mockito.doAnswer;
|
|
52 | 53 | import static org.neo4j.driver.testutil.TestUtil.verifyRunRx;
|
53 | 54 |
|
54 | 55 | import java.util.Collections;
|
| 56 | +import java.util.List; |
55 | 57 | import java.util.Set;
|
56 | 58 | import java.util.concurrent.CompletableFuture;
|
57 | 59 | import java.util.concurrent.CompletionStage;
|
58 | 60 | import java.util.concurrent.ExecutionException;
|
59 | 61 | import java.util.function.Consumer;
|
| 62 | +import java.util.function.Function; |
60 | 63 | import java.util.function.Supplier;
|
61 | 64 | import java.util.stream.Stream;
|
| 65 | +import org.junit.jupiter.api.Named; |
62 | 66 | import org.junit.jupiter.api.Test;
|
63 | 67 | import org.junit.jupiter.params.ParameterizedTest;
|
64 | 68 | import org.junit.jupiter.params.provider.Arguments;
|
|
72 | 76 | import org.neo4j.driver.exceptions.ConnectionReadTimeoutException;
|
73 | 77 | import org.neo4j.driver.exceptions.Neo4jException;
|
74 | 78 | import org.neo4j.driver.exceptions.TransactionTerminatedException;
|
| 79 | +import org.neo4j.driver.internal.DatabaseBookmark; |
75 | 80 | import org.neo4j.driver.internal.FailableCursor;
|
76 | 81 | import org.neo4j.driver.internal.InternalBookmark;
|
77 | 82 | import org.neo4j.driver.internal.messaging.BoltProtocol;
|
78 | 83 | import org.neo4j.driver.internal.messaging.v4.BoltProtocolV4;
|
| 84 | +import org.neo4j.driver.internal.messaging.v53.BoltProtocolV53; |
79 | 85 | import org.neo4j.driver.internal.spi.Connection;
|
80 | 86 | import org.neo4j.driver.internal.spi.ResponseHandler;
|
81 | 87 |
|
@@ -476,6 +482,76 @@ void shouldHandleTerminationWhenAlreadyTerminated() throws ExecutionException, I
|
476 | 482 | assertEquals(exception, actualException);
|
477 | 483 | }
|
478 | 484 |
|
| 485 | + @ParameterizedTest |
| 486 | + @MethodSource("transactionClosingTestParams") |
| 487 | + void shouldThrowOnRunningNewQueriesWhenTransactionIsClosing(TransactionClosingTestParams testParams) { |
| 488 | + // Given |
| 489 | + var boltProtocol = mock(BoltProtocol.class); |
| 490 | + given(boltProtocol.version()).willReturn(BoltProtocolV53.VERSION); |
| 491 | + var closureStage = new CompletableFuture<DatabaseBookmark>(); |
| 492 | + var connection = connectionMock(boltProtocol); |
| 493 | + given(boltProtocol.beginTransaction(eq(connection), any(), any(), any(), any())) |
| 494 | + .willReturn(completedFuture(null)); |
| 495 | + given(boltProtocol.commitTransaction(connection)).willReturn(closureStage); |
| 496 | + given(boltProtocol.rollbackTransaction(connection)).willReturn(closureStage.thenApply(ignored -> null)); |
| 497 | + var tx = beginTx(connection); |
| 498 | + |
| 499 | + // When |
| 500 | + testParams.closeAction().apply(tx); |
| 501 | + var exception = assertThrows( |
| 502 | + ClientException.class, () -> await(testParams.runAction().apply(tx))); |
| 503 | + |
| 504 | + // Then |
| 505 | + assertEquals(testParams.expectedMessage(), exception.getMessage()); |
| 506 | + } |
| 507 | + |
| 508 | + static List<Arguments> transactionClosingTestParams() { |
| 509 | + Function<UnmanagedTransaction, CompletionStage<?>> asyncRun = tx -> tx.runAsync(new Query("query")); |
| 510 | + Function<UnmanagedTransaction, CompletionStage<?>> reactiveRun = tx -> tx.runRx(new Query("query")); |
| 511 | + return List.of( |
| 512 | + Arguments.of(Named.of( |
| 513 | + "commit and run async", |
| 514 | + new TransactionClosingTestParams( |
| 515 | + UnmanagedTransaction::commitAsync, |
| 516 | + asyncRun, |
| 517 | + "Cannot run more queries in this transaction, it is being committed"))), |
| 518 | + Arguments.of(Named.of( |
| 519 | + "commit and run reactive", |
| 520 | + new TransactionClosingTestParams( |
| 521 | + UnmanagedTransaction::commitAsync, |
| 522 | + reactiveRun, |
| 523 | + "Cannot run more queries in this transaction, it is being committed"))), |
| 524 | + Arguments.of(Named.of( |
| 525 | + "rollback and run async", |
| 526 | + new TransactionClosingTestParams( |
| 527 | + UnmanagedTransaction::rollbackAsync, |
| 528 | + asyncRun, |
| 529 | + "Cannot run more queries in this transaction, it is being rolled back"))), |
| 530 | + Arguments.of(Named.of( |
| 531 | + "rollback and run reactive", |
| 532 | + new TransactionClosingTestParams( |
| 533 | + UnmanagedTransaction::rollbackAsync, |
| 534 | + reactiveRun, |
| 535 | + "Cannot run more queries in this transaction, it is being rolled back"))), |
| 536 | + Arguments.of(Named.of( |
| 537 | + "close and run async", |
| 538 | + new TransactionClosingTestParams( |
| 539 | + UnmanagedTransaction::closeAsync, |
| 540 | + asyncRun, |
| 541 | + "Cannot run more queries in this transaction, it is being rolled back"))), |
| 542 | + Arguments.of(Named.of( |
| 543 | + "close and run reactive", |
| 544 | + new TransactionClosingTestParams( |
| 545 | + UnmanagedTransaction::closeAsync, |
| 546 | + reactiveRun, |
| 547 | + "Cannot run more queries in this transaction, it is being rolled back")))); |
| 548 | + } |
| 549 | + |
| 550 | + private record TransactionClosingTestParams( |
| 551 | + Function<UnmanagedTransaction, CompletionStage<?>> closeAction, |
| 552 | + Function<UnmanagedTransaction, CompletionStage<?>> runAction, |
| 553 | + String expectedMessage) {} |
| 554 | + |
479 | 555 | private static UnmanagedTransaction beginTx(Connection connection) {
|
480 | 556 | return beginTx(connection, Collections.emptySet());
|
481 | 557 | }
|
|
0 commit comments