'Quarkus upgrade complaining regarding vertx thread in tests
I have recently upgraded quarkus to 2.9.0.CR1 and am now having issues in some of my tests
I am using reactive panache in this, through the repository pattern.
Note: i am able to access the db fine if i launch the app and try to manually test.
My test:
@QuarkusTest
public class MyTest {
@InjectMock
MYRepository repository;
@Test
public void test_a() {
...
myService.callMethod().await().indefinitely();
...
}
}
My Service being tested:
@ApplicationScoped
public class MyService {
@Inject
MyRepository repository;
@Inject
SessionFactory sessionFactory;
public Uni<MyDto> callMethod() {
return Uni.createFrom().item(...)
...
.flatMap(a -> sessionFactory.openSession()
.chain(session -> session
.withTransaction(s -> ..../*some db fetch's and persists */)
.eventually(session::close)));
}
}
I get the following exceptions however:
Multiple exceptions caught:
[Exception 0] io.smallrye.mutiny.CompositeException: Multiple exceptions caught:
[Exception 0] java.lang.IllegalStateException: HR000069: Detected use of the reactive Session from a different Thread than the one which was used to open the reactive Session - this suggests an invalid integration; original thread [166]: 'vert.x-eventloop-thread-3' current Thread [129]: 'executor-thread-0'
[Exception 1] java.lang.IllegalStateException: HR000068: This method should exclusively be invoked from a Vert.x EventLoop thread; currently running on thread 'executor-thread-0'
[Exception 1] java.lang.IllegalStateException: HR000069: Detected use of the reactive Session from a different Thread than the one which was used to open the reactive Session - this suggests an invalid integration; original thread [166]: 'vert.x-eventloop-thread-3' current Thread [129]: 'executor-thread-0'
at io.smallrye.mutiny.groups.UniOnItemOrFailure.lambda$call$1(UniOnItemOrFailure.java:75)
at io.smallrye.context.impl.wrappers.SlowContextualBiFunction.apply(SlowContextualBiFunction.java:21)
at io.smallrye.mutiny.operators.uni.UniOnItemOrFailureFlatMap$UniOnItemOrFailureFlatMapProcessor.performInnerSubscription(UniOnItemOrFailureFlatMap.java:86)
at io.smallrye.mutiny.operators.uni.UniOnItemOrFailureFlatMap$UniOnItemOrFailureFlatMapProcessor.onFailure(UniOnItemOrFailureFlatMap.java:65)
at io.smallrye.mutiny.operators.uni.UniOperatorProcessor.onFailure(UniOperatorProcessor.java:54)
at io.smallrye.mutiny.helpers.EmptyUniSubscription.propagateFailureEvent(EmptyUniSubscription.java:40)
at io.smallrye.mutiny.operators.uni.builders.UniCreateFromCompletionStage.subscribe(UniCreateFromCompletionStage.java:26)
at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
at io.smallrye.mutiny.operators.uni.UniRunSubscribeOn.lambda$subscribe$0(UniRunSubscribeOn.java:27)
at org.hibernate.reactive.context.impl.VertxContext.execute(VertxContext.java:78)
at io.smallrye.mutiny.operators.uni.UniRunSubscribeOn.subscribe(UniRunSubscribeOn.java:25)
at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
at io.smallrye.mutiny.operators.uni.UniOnItemOrFailureFlatMap.subscribe(UniOnItemOrFailureFlatMap.java:27)
at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
at io.smallrye.mutiny.operators.uni.UniOnItemOrFailureFlatMap$UniOnItemOrFailureFlatMapProcessor.performInnerSubscription(UniOnItemOrFailureFlatMap.java:99)
at io.smallrye.mutiny.operators.uni.UniOnItemOrFailureFlatMap$UniOnItemOrFailureFlatMapProcessor.onFailure(UniOnItemOrFailureFlatMap.java:65)
at io.smallrye.mutiny.operators.uni.UniOnItemOrFailureConsume$UniOnItemOrFailureConsumeProcessor.onFailure(UniOnItemOrFailureConsume.java:46)
at io.smallrye.mutiny.operators.uni.UniOperatorProcessor.onFailure(UniOperatorProcessor.java:54)
at io.smallrye.mutiny.operators.uni.UniOperatorProcessor.onFailure(UniOperatorProcessor.java:54)
at io.smallrye.mutiny.operators.uni.UniOperatorProcessor.onFailure(UniOperatorProcessor.java:54)
at io.smallrye.mutiny.operators.uni.UniOnCancellationCall$UniOnCancellationCallProcessor.onFailure(UniOnCancellationCall.java:59)
at io.smallrye.mutiny.operators.uni.UniOnFailureFlatMap$UniOnFailureFlatMapProcessor.performInnerSubscription(UniOnFailureFlatMap.java:94)
at io.smallrye.mutiny.operators.uni.UniOnFailureFlatMap$UniOnFailureFlatMapProcessor.dispatch(UniOnFailureFlatMap.java:83)
at io.smallrye.mutiny.operators.uni.UniOnFailureFlatMap$UniOnFailureFlatMapProcessor.onFailure(UniOnFailureFlatMap.java:60)
at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.performInnerSubscription(UniOnItemTransformToUni.java:73)
at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:57)
at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:60)
at io.smallrye.mutiny.operators.uni.UniOnItemTransform$UniOnItemTransformProcessor.onItem(UniOnItemTransform.java:43)
at io.smallrye.mutiny.operators.uni.builders.UniCreateFromCompletionStage$CompletionStageUniSubscription.forwardResult(UniCreateFromCompletionStage.java:63)
at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:863)
at java.base/java.util.concurrent.CompletableFuture.uniWhenCompleteStage(CompletableFuture.java:887)
at java.base/java.util.concurrent.CompletableFuture.whenComplete(CompletableFuture.java:2325)
at java.base/java.util.concurrent.CompletableFuture.whenComplete(CompletableFuture.java:144)
at io.smallrye.mutiny.operators.uni.builders.UniCreateFromCompletionStage$CompletionStageUniSubscription.forward(UniCreateFromCompletionStage.java:51)
at io.smallrye.mutiny.operators.uni.builders.UniCreateFromCompletionStage.subscribe(UniCreateFromCompletionStage.java:35)
at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
at io.smallrye.mutiny.operators.uni.UniOnItemTransform.subscribe(UniOnItemTransform.java:22)
at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.performInnerSubscription(UniOnItemTransformToUni.java:81)
at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:57)
at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:60)
at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:60)
at io.smallrye.mutiny.operators.uni.UniOnItemTransform$UniOnItemTransformProcessor.onItem(UniOnItemTransform.java:43)
at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:60)
at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:60)
at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:60)
at io.smallrye.mutiny.operators.uni.UniOnItemTransform$UniOnItemTransformProcessor.onItem(UniOnItemTransform.java:43)
at io.smallrye.mutiny.operators.uni.UniOnItemConsume$UniOnItemComsumeProcessor.onItem(UniOnItemConsume.java:43)
at io.smallrye.mutiny.operators.uni.UniOnItemConsume$UniOnItemComsumeProcessor.onItem(UniOnItemConsume.java:43)
at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:60)
at io.smallrye.mutiny.operators.uni.builders.UniCreateFromFuture.lambda$dispatchDeferredResult$1(UniCreateFromFuture.java:83)
at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:548)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:833)
Suppressed: java.lang.IllegalStateException: HR000069: Detected use of the reactive Session from a different Thread than the one which was used to open the reactive Session - this suggests an invalid integration; original thread [166]: 'vert.x-eventloop-thread-3' current Thread [129]: 'executor-thread-0'
at org.hibernate.reactive.common.InternalStateAssertions.assertCurrentThreadMatches(InternalStateAssertions.java:46)
at org.hibernate.reactive.session.impl.ReactiveSessionImpl.threadCheck(ReactiveSessionImpl.java:154)
at org.hibernate.reactive.session.impl.ReactiveSessionImpl.checkOpen(ReactiveSessionImpl.java:1557)
at org.hibernate.internal.AbstractSharedSessionContract.checkOpenOrWaitingForAutoClose(AbstractSharedSessionContract.java:413)
at org.hibernate.internal.SessionImpl.closeWithoutOpenChecks(SessionImpl.java:411)
at org.hibernate.internal.SessionImpl.close(SessionImpl.java:398)
at org.hibernate.reactive.session.impl.ReactiveSessionImpl.reactiveClose(ReactiveSessionImpl.java:1489)
at io.smallrye.context.impl.wrappers.SlowContextualSupplier.get(SlowContextualSupplier.java:21)
at io.smallrye.mutiny.operators.uni.builders.UniCreateFromCompletionStage.subscribe(UniCreateFromCompletionStage.java:24)
... 51 more
Caused by: io.smallrye.mutiny.CompositeException: Multiple exceptions caught:
[Exception 0] java.lang.IllegalStateException: HR000069: Detected use of the reactive Session from a different Thread than the one which was used to open the reactive Session - this suggests an invalid integration; original thread [166]: 'vert.x-eventloop-thread-3' current Thread [129]: 'executor-thread-0'
[Exception 1] java.lang.IllegalStateException: HR000068: This method should exclusively be invoked from a Vert.x EventLoop thread; currently running on thread 'executor-thread-0'
... 37 more
Suppressed: java.lang.IllegalStateException: HR000068: This method should exclusively be invoked from a Vert.x EventLoop thread; currently running on thread 'executor-thread-0'
at org.hibernate.reactive.common.InternalStateAssertions.assertUseOnEventLoop(InternalStateAssertions.java:40)
at org.hibernate.reactive.session.impl.ReactiveSessionImpl.getReactiveConnection(ReactiveSessionImpl.java:1478)
at org.hibernate.reactive.mutiny.impl.MutinySessionImpl$Transaction.rollback(MutinySessionImpl.java:467)
at io.smallrye.context.impl.wrappers.SlowContextualSupplier.get(SlowContextualSupplier.java:21)
at io.smallrye.mutiny.groups.UniOnFailure.lambda$call$5(UniOnFailure.java:133)
at io.smallrye.context.impl.wrappers.SlowContextualFunction.apply(SlowContextualFunction.java:21)
at io.smallrye.mutiny.groups.UniOnFailure.lambda$call$4(UniOnFailure.java:102)
at io.smallrye.context.impl.wrappers.SlowContextualFunction.apply(SlowContextualFunction.java:21)
at io.smallrye.mutiny.operators.uni.UniOnFailureFlatMap$UniOnFailureFlatMapProcessor.performInnerSubscription(UniOnFailureFlatMap.java:92)
... 36 more
Caused by: java.lang.IllegalStateException: HR000069: Detected use of the reactive Session from a different Thread than the one which was used to open the reactive Session - this suggests an invalid integration; original thread [166]: 'vert.x-eventloop-thread-3' current Thread [129]: 'executor-thread-0'
at org.hibernate.reactive.common.InternalStateAssertions.assertCurrentThreadMatches(InternalStateAssertions.java:46)
at org.hibernate.reactive.session.impl.ReactiveSessionImpl.threadCheck(ReactiveSessionImpl.java:154)
at org.hibernate.reactive.session.impl.ReactiveSessionImpl.getReactiveActionQueue(ReactiveSessionImpl.java:164)
at org.hibernate.reactive.mutiny.impl.MutinySessionImpl$Transaction.beforeCompletion(MutinySessionImpl.java:475)
at io.smallrye.context.impl.wrappers.SlowContextualSupplier.get(SlowContextualSupplier.java:21)
at io.smallrye.mutiny.groups.UniOnItem.lambda$call$3(UniOnItem.java:99)
at io.smallrye.context.impl.wrappers.SlowContextualFunction.apply(SlowContextualFunction.java:21)
at io.smallrye.mutiny.groups.UniOnItem.lambda$call$2(UniOnItem.java:79)
at io.smallrye.context.impl.wrappers.SlowContextualFunction.apply(SlowContextualFunction.java:21)
at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.performInnerSubscription(UniOnItemTransformToUni.java:68)
... 33 more
Edit: Beefier example after some more fixes trying to get this to work:
Test:
@Test
@TestReactiveTransaction
public void test_SanintisationAccess_NotExclusiveTenant(UniAsserter uniAsserter) {
final CustomerDto creationResult = given()
.when()
.header("Content-Type", MediaTypes.JSON_TYPE)
.header(Headers.TENANT, TENANT)
.header(Headers.EXCLUSIVE_TENANT, exclusiveTenant)
.and()
.body("{}")
.post(BASE_URL)
.then()
.extract().response().getBody().as(CustomerDto.class);
// db validation
uniAsserter.assertThat(() -> dbUtils.getAllTableEntries(CustomerActive.TABLE), activeCustomers -> {
assertEquals(1, activeCustomers.size());
});
uniAsserter.assertThat(() -> dbUtils.getAllTableEntries(CustomerAudit.TABLE), auditRecords -> {
assertEquals(1, auditRecords.size());
});
final Supplier<Uni<Row>> auditCustomer = () -> dbUtils.getAllTableEntries(CustomerAudit.TABLE).map(auditRecords -> auditRecords.get(0));
final Response deactivationResponse = given()
.when()
.delete(URL_ID, new HashMap<>(){{
put(PATH_ID, creationResult.getId());
}})
.then()
.extract().response();
// response validation
assertEquals(204, deactivationResponse.getStatusCode(), () -> "Got: " + deactivationResponse.prettyPrint());
final Response response = given()
.when()
.delete(URL_ID, new HashMap<>(){{
put(PATH_ID, creationResult.getId());
}})
.then()
.extract().response();
assertEquals(403, response.getStatusCode(), () -> "Got: " + response.prettyPrint());
}
Controller content:
@POST
@Path("/customer")
@ReactiveTransactional
public Uni<CustomerDto> createCustomer(CustomerPostDto customerPostDto) {
assertNotEmpty(customerPostDto, "customer creation details");
return myService.myMethod(customerPostDto);
}
Solution 1:[1]
You can't invoke Hibernate Reactive in a unit test like that.
You have to ensure that the call to the database is done on a Vert.x thread and as part of a request context. This is not trivial to do with stock JUnit, but Quarkus does provide some utilities to help you do that.
Essentially you would write something like:
@Test
public void test_a(UniAsserter uniAsserter) {
uniAsserter.assertThat(() -> myService.callMethod(), () -> {
// perform some assertion
});
}
See this example for more details.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | geoand |