I have a quarkus application that I am trying to test using Restassured I am however getting this error when testing:
[org.jbo.res.rea.ser.cor.RuntimeExceptionMapper] (vert.x-eventloop-thread-1) A blocking operation occurred on the IO thread. This likely means you need to annotate my.package.MyController#update(class my.package.MyRequestDto) with @io.smallrye.common.annotation.Blocking. Alternatively you can annotate the class my.package.MyController to make every method on the class blocking, or annotate your sub class of the javax.ws.rs.core.Application class to make the whole application blocking
If i run this application and test manually using postman this does not seem to happen so it is a matter of test setup that seems to be the issue.
My test is as follows:
@QuarkusTest
public class MyTest {
@Test
@TestReactiveTransaction
public void test_A() {
Response response = given()
.when()
.accept(MediaTypes.JSON_TYPE)
.contentType(MediaTypes.JSON_TYPE)
.body("{myRequestJsonHere}")
.patch("/path/to/api")
.then()
.extract().response();
// asserts
}
}
Inside my controller:
@Path("/path/to/api")
@ApplicationScoped
public class MyController{
@Inject MyService service;
@PATCH
public Uni<MyResultType> update(@NotNull @RequestBody @Valid MyRequestDto request) {
return service.update(request);
}
}
My service:
@ApplicationScoped
public class MyService {
@Inject MyRepository repository;
@Transactional
public Uni<MyResultType> update(MyRequestDto request) {
return repository.findAll().firstResult()
.onItem().transform(l -> mapping here))
.flatMap(repository::persistAndFlush);
}
}
My repository:
public interface MyRepository extends PanacheRepository<MyResultType> {
}
I have also tried wrapping the full test content in a UniAsserter.execute(() -> { });
but still got the same issue.
Is there some more setup I need to do to ensure the thread is used properly?
@Transactional
doesn't work with Reactive Panache or Hibernate Reactive.
You can use @ReactiveTransactional
or Panache.withTransaction
.
You shouldn't use @TestReactiveTransactional
for the test. You are simulating a Rest call, there's no reason to open a transaction.
I think what's happening is that you are starting a reactive transaction and then RestAssure will call the REST API and block the client until the result is received.I suspect this is what's causing the issue.
You can change the code of the test to:
@QuarkusTest
public class MyTest {
@Test
public void test_A() {
Response response = given()
.when()
.accept(MediaTypes.JSON_TYPE)
.contentType(MediaTypes.JSON_TYPE)
.body("{myRequestJsonHere}")
.patch("/path/to/api")
.then()
.extract().response();
}
}
The service becomes:
@ApplicationScoped
public class MyService {
@Inject MyRepository repository;
@ReactiveTransactional
public Uni<MyResultType> update(MyRequestDto request) {
return repository
.findAll()
.firstResult()
.map(l -> /* update the entity... */ );
}
}
The persist should only be necessary if you are creating a new entity. You can add it back if you need it.