From 14dd05e264418713b3e0fa50424aa6fa34feefb1 Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Fri, 13 Oct 2023 09:46:48 +0200 Subject: [PATCH 1/2] Reactive routes: virtual threads support - resolves #36430 --- docs/src/main/asciidoc/reactive-routes.adoc | 8 +- docs/src/main/asciidoc/virtual-threads.adoc | 1 + .../web/deployment/HandlerDescriptor.java | 11 ++- .../deployment/ReactiveRoutesProcessor.java | 13 +++- .../vertx/web/runtime/VertxWebRecorder.java | 4 + .../runtime/VirtualThreadsRouteHandler.java | 36 +++++++++ integration-tests/virtual-threads/pom.xml | 3 +- .../reactive-routes-virtual-threads/pom.xml | 76 +++++++++++++++++++ .../virtual/vertx/web/AssertHelper.java | 71 +++++++++++++++++ .../io/quarkus/virtual/vertx/web/Routes.java | 16 ++++ .../src/main/resources/application.properties | 3 + .../vertx/web}/RunOnVirtualThreadIT.java | 2 +- .../vertx/web/RunOnVirtualThreadTest.java | 25 ++++++ .../scheduler/RunOnVirtualThreadIT.java | 8 ++ .../RunOnVirtualThreadTest.java | 2 +- 15 files changed, 266 insertions(+), 13 deletions(-) create mode 100644 extensions/reactive-routes/runtime/src/main/java/io/quarkus/vertx/web/runtime/VirtualThreadsRouteHandler.java create mode 100644 integration-tests/virtual-threads/reactive-routes-virtual-threads/pom.xml create mode 100644 integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/java/io/quarkus/virtual/vertx/web/AssertHelper.java create mode 100644 integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/java/io/quarkus/virtual/vertx/web/Routes.java create mode 100644 integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/resources/application.properties rename integration-tests/virtual-threads/{scheduler-virtual-threads/src/test/java/io/quarkus/virtual/mail => reactive-routes-virtual-threads/src/test/java/io/quarkus/virtual/vertx/web}/RunOnVirtualThreadIT.java (78%) create mode 100644 integration-tests/virtual-threads/reactive-routes-virtual-threads/src/test/java/io/quarkus/virtual/vertx/web/RunOnVirtualThreadTest.java create mode 100644 integration-tests/virtual-threads/scheduler-virtual-threads/src/test/java/io/quarkus/virtual/scheduler/RunOnVirtualThreadIT.java rename integration-tests/virtual-threads/scheduler-virtual-threads/src/test/java/io/quarkus/virtual/{mail => scheduler}/RunOnVirtualThreadTest.java (97%) diff --git a/docs/src/main/asciidoc/reactive-routes.adoc b/docs/src/main/asciidoc/reactive-routes.adoc index 496ffac6e7e7a..6dd76ecb21f89 100644 --- a/docs/src/main/asciidoc/reactive-routes.adoc +++ b/docs/src/main/asciidoc/reactive-routes.adoc @@ -138,7 +138,7 @@ public void blocking(RoutingContext rc) { // ... } ---- -When `@Blocking` is used, it ignores the `type` attribute of `@Route`. +When `@Blocking` is used, the `type` attribute of the `@Route` is ignored. ==== The `@Route` annotation is repeatable and so you can declare several routes for a single method: @@ -164,6 +164,12 @@ String person() { ---- <1> If the `accept` header matches `text/html`, we set the content type automatically to `text/html`. +=== Executing route on a virtual thread + +You can annotate a route method with `@io.smallrye.common.annotation.RunOnVirtualThread` in order to execute it on a virtual thread. +However, keep in mind that not everything can run safely on virtual threads. +You should read the xref:virtual-threads.adoc#run-code-on-virtual-threads-using-runonvirtualthread[Virtual thread support reference] carefully and get acquainted with all the details. + === Handling conflicting routes You may end up with multiple routes matching a given path. diff --git a/docs/src/main/asciidoc/virtual-threads.adoc b/docs/src/main/asciidoc/virtual-threads.adoc index 6851a32c28455..e409077fdb982 100644 --- a/docs/src/main/asciidoc/virtual-threads.adoc +++ b/docs/src/main/asciidoc/virtual-threads.adoc @@ -79,6 +79,7 @@ In this scenario, it is worse than useless to have thousands of threads if we ha Even worse, when running a CPU-bound workload on a virtual thread, the virtual thread monopolizes the carrier thread on which it is mounted. It will either reduce the chance for the other virtual thread to run or will start creating new carrier threads, leading to high memory usage. +[[run-code-on-virtual-threads-using-runonvirtualthread]] == Run code on virtual threads using @RunOnVirtualThread In Quarkus, the support of virtual thread is implemented using the link:{runonvthread}[@RunOnVirtualThread] annotation. diff --git a/extensions/reactive-routes/deployment/src/main/java/io/quarkus/vertx/web/deployment/HandlerDescriptor.java b/extensions/reactive-routes/deployment/src/main/java/io/quarkus/vertx/web/deployment/HandlerDescriptor.java index 61eafeee5f513..b4919b73d26a2 100644 --- a/extensions/reactive-routes/deployment/src/main/java/io/quarkus/vertx/web/deployment/HandlerDescriptor.java +++ b/extensions/reactive-routes/deployment/src/main/java/io/quarkus/vertx/web/deployment/HandlerDescriptor.java @@ -6,7 +6,6 @@ import org.jboss.jandex.Type.Kind; import io.quarkus.hibernate.validator.spi.BeanValidationAnnotationsBuildItem; -import io.quarkus.vertx.http.runtime.HandlerType; /** * Describe a request handler. @@ -15,15 +14,15 @@ class HandlerDescriptor { private final MethodInfo method; private final BeanValidationAnnotationsBuildItem validationAnnotations; - private final HandlerType handlerType; + private final boolean failureHandler; private final Type payloadType; private final String[] contentTypes; - HandlerDescriptor(MethodInfo method, BeanValidationAnnotationsBuildItem bvAnnotations, HandlerType handlerType, + HandlerDescriptor(MethodInfo method, BeanValidationAnnotationsBuildItem bvAnnotations, boolean failureHandler, String[] producedTypes) { this.method = method; this.validationAnnotations = bvAnnotations; - this.handlerType = handlerType; + this.failureHandler = failureHandler; Type returnType = method.returnType(); if (returnType.kind() == Kind.VOID) { payloadType = null; @@ -120,8 +119,8 @@ boolean isPayloadMutinyBuffer() { return type.name().equals(DotNames.MUTINY_BUFFER); } - HandlerType getHandlerType() { - return handlerType; + boolean isFailureHandler() { + return failureHandler; } } diff --git a/extensions/reactive-routes/deployment/src/main/java/io/quarkus/vertx/web/deployment/ReactiveRoutesProcessor.java b/extensions/reactive-routes/deployment/src/main/java/io/quarkus/vertx/web/deployment/ReactiveRoutesProcessor.java index 3f6872a54ac88..d36890773bcc2 100644 --- a/extensions/reactive-routes/deployment/src/main/java/io/quarkus/vertx/web/deployment/ReactiveRoutesProcessor.java +++ b/extensions/reactive-routes/deployment/src/main/java/io/quarkus/vertx/web/deployment/ReactiveRoutesProcessor.java @@ -445,7 +445,7 @@ public boolean test(String name) { if (routeHandler == null) { String handlerClass = generateHandler( new HandlerDescriptor(businessMethod.getMethod(), beanValidationAnnotations.orElse(null), - handlerType, produces), + handlerType == HandlerType.FAILURE, produces), businessMethod.getBean(), businessMethod.getMethod(), classOutput, transformedAnnotations, routeString, reflectiveHierarchy, produces.length > 0 ? produces[0] : null, validatorAvailable, index); @@ -458,6 +458,13 @@ public boolean test(String name) { // Wrap the route handler if necessary // Note that route annotations with the same values share a single handler implementation routeHandler = recorder.compressRouteHandler(routeHandler, businessMethod.getCompression()); + if (businessMethod.getMethod().hasDeclaredAnnotation(DotNames.RUN_ON_VIRTUAL_THREAD)) { + LOGGER.debugf("Route %s#%s() will be executed on a virtual thread", + businessMethod.getMethod().declaringClass().name(), businessMethod.getMethod().name()); + routeHandler = recorder.runOnVirtualThread(routeHandler); + // The handler must be executed on the event loop + handlerType = HandlerType.NORMAL; + } RouteMatcher matcher = new RouteMatcher(path, regex, produces, consumes, methods, order); matchers.put(matcher, businessMethod.getMethod()); @@ -489,7 +496,7 @@ public boolean test(String name) { for (AnnotatedRouteFilterBuildItem filterMethod : routeFilterBusinessMethods) { String handlerClass = generateHandler( - new HandlerDescriptor(filterMethod.getMethod(), beanValidationAnnotations.orElse(null), HandlerType.NORMAL, + new HandlerDescriptor(filterMethod.getMethod(), beanValidationAnnotations.orElse(null), false, new String[0]), filterMethod.getBean(), filterMethod.getMethod(), classOutput, transformedAnnotations, filterMethod.getRouteFilter().toString(true), reflectiveHierarchy, null, validatorAvailable, index); @@ -785,7 +792,7 @@ void implementInvoke(HandlerDescriptor descriptor, BeanInfo bean, MethodInfo met defaultProduces == null ? invoke.loadNull() : invoke.load(defaultProduces)); // For failure handlers attempt to match the failure type - if (descriptor.getHandlerType() == HandlerType.FAILURE) { + if (descriptor.isFailureHandler()) { Type failureType = getFailureType(parameters, index); if (failureType != null) { ResultHandle failure = invoke.invokeInterfaceMethod(Methods.FAILURE, routingContext); diff --git a/extensions/reactive-routes/runtime/src/main/java/io/quarkus/vertx/web/runtime/VertxWebRecorder.java b/extensions/reactive-routes/runtime/src/main/java/io/quarkus/vertx/web/runtime/VertxWebRecorder.java index 6fd9f8519fc71..e87bf25a4a50e 100644 --- a/extensions/reactive-routes/runtime/src/main/java/io/quarkus/vertx/web/runtime/VertxWebRecorder.java +++ b/extensions/reactive-routes/runtime/src/main/java/io/quarkus/vertx/web/runtime/VertxWebRecorder.java @@ -51,6 +51,10 @@ public Handler createHandler(String handlerClassName) { } } + public Handler runOnVirtualThread(Handler routeHandler) { + return new VirtualThreadsRouteHandler(routeHandler); + } + public Handler compressRouteHandler(Handler routeHandler, HttpCompression compression) { if (httpBuildTimeConfig.enableCompression) { return new HttpCompressionHandler(routeHandler, compression, diff --git a/extensions/reactive-routes/runtime/src/main/java/io/quarkus/vertx/web/runtime/VirtualThreadsRouteHandler.java b/extensions/reactive-routes/runtime/src/main/java/io/quarkus/vertx/web/runtime/VirtualThreadsRouteHandler.java new file mode 100644 index 0000000000000..4e0f7b3d2540c --- /dev/null +++ b/extensions/reactive-routes/runtime/src/main/java/io/quarkus/vertx/web/runtime/VirtualThreadsRouteHandler.java @@ -0,0 +1,36 @@ +package io.quarkus.vertx.web.runtime; + +import io.quarkus.vertx.core.runtime.VertxCoreRecorder; +import io.quarkus.vertx.core.runtime.context.VertxContextSafetyToggle; +import io.quarkus.virtual.threads.VirtualThreadsRecorder; +import io.smallrye.common.vertx.VertxContext; +import io.vertx.core.Context; +import io.vertx.core.Handler; +import io.vertx.ext.web.RoutingContext; + +public class VirtualThreadsRouteHandler implements Handler { + + private final Handler routeHandler; + + public VirtualThreadsRouteHandler(Handler routeHandler) { + this.routeHandler = routeHandler; + } + + @Override + public void handle(RoutingContext context) { + Context vertxContext = VertxContext.getOrCreateDuplicatedContext(VertxCoreRecorder.getVertx().get()); + VertxContextSafetyToggle.setContextSafe(vertxContext, true); + vertxContext.runOnContext(new Handler() { + @Override + public void handle(Void event) { + VirtualThreadsRecorder.getCurrent().execute(new Runnable() { + @Override + public void run() { + routeHandler.handle(context); + } + }); + } + }); + } + +} diff --git a/integration-tests/virtual-threads/pom.xml b/integration-tests/virtual-threads/pom.xml index 853d39c10638b..e348c119ee410 100644 --- a/integration-tests/virtual-threads/pom.xml +++ b/integration-tests/virtual-threads/pom.xml @@ -35,7 +35,8 @@ vertx-event-bus-virtual-threads scheduler-virtual-threads quartz-virtual-threads - virtual-threads-disabled + virtual-threads-disabled + reactive-routes-virtual-threads diff --git a/integration-tests/virtual-threads/reactive-routes-virtual-threads/pom.xml b/integration-tests/virtual-threads/reactive-routes-virtual-threads/pom.xml new file mode 100644 index 0000000000000..e1b096a0c4cff --- /dev/null +++ b/integration-tests/virtual-threads/reactive-routes-virtual-threads/pom.xml @@ -0,0 +1,76 @@ + + + 4.0.0 + + + quarkus-virtual-threads-integration-tests-parent + io.quarkus + 999-SNAPSHOT + + + quarkus-integration-test-virtual-threads-reactive-routes + Quarkus - Integration Tests - Virtual Threads - Reactive Routes + + + + io.quarkus + quarkus-reactive-routes + + + io.quarkus + quarkus-junit5 + test + + + io.quarkus.junit5 + junit5-virtual-threads + test + + + io.rest-assured + rest-assured + test + + + org.awaitility + awaitility + test + + + org.assertj + assertj-core + test + + + + + io.quarkus + quarkus-reactive-routes-deployment + ${project.version} + pom + test + + + * + * + + + + + + + + + io.quarkus + quarkus-maven-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + + + + + diff --git a/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/java/io/quarkus/virtual/vertx/web/AssertHelper.java b/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/java/io/quarkus/virtual/vertx/web/AssertHelper.java new file mode 100644 index 0000000000000..a96082b02791e --- /dev/null +++ b/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/java/io/quarkus/virtual/vertx/web/AssertHelper.java @@ -0,0 +1,71 @@ +package io.quarkus.virtual.vertx.web; + +import java.lang.reflect.Method; + +import io.quarkus.arc.Arc; +import io.smallrye.common.vertx.VertxContext; +import io.vertx.core.Vertx; + +public class AssertHelper { + + /** + * Asserts that the current method: + * - runs on a duplicated context + * - runs on a virtual thread + * - has the request scope activated + */ + public static void assertEverything() { + assertThatTheRequestScopeIsActive(); + assertThatItRunsOnVirtualThread(); + assertThatItRunsOnADuplicatedContext(); + } + + public static void assertThatTheRequestScopeIsActive() { + if (!Arc.container().requestContext().isActive()) { + throw new AssertionError(("Expected the request scope to be active")); + } + } + + public static void assertThatItRunsOnADuplicatedContext() { + var context = Vertx.currentContext(); + if (context == null) { + throw new AssertionError("The method does not run on a Vert.x context"); + } + if (!VertxContext.isOnDuplicatedContext()) { + throw new AssertionError("The method does not run on a Vert.x **duplicated** context"); + } + } + + public static void assertThatItRunsOnVirtualThread() { + // We cannot depend on a Java 20. + try { + Method isVirtual = Thread.class.getMethod("isVirtual"); + isVirtual.setAccessible(true); + boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); + if (!virtual) { + throw new AssertionError("Thread " + Thread.currentThread() + " is not a virtual thread"); + } + } catch (Exception e) { + throw new AssertionError( + "Thread " + Thread.currentThread() + " is not a virtual thread - cannot invoke Thread.isVirtual()", e); + } + } + + public static void assertNotOnVirtualThread() { + // We cannot depend on a Java 20. + try { + Method isVirtual = Thread.class.getMethod("isVirtual"); + isVirtual.setAccessible(true); + boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); + if (virtual) { + throw new AssertionError("Thread " + Thread.currentThread() + " is a virtual thread"); + } + } catch (Exception e) { + // Trying using Thread name. + var name = Thread.currentThread().toString(); + if (name.toLowerCase().contains("virtual")) { + throw new AssertionError("Thread " + Thread.currentThread() + " seems to be a virtual thread"); + } + } + } +} diff --git a/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/java/io/quarkus/virtual/vertx/web/Routes.java b/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/java/io/quarkus/virtual/vertx/web/Routes.java new file mode 100644 index 0000000000000..6e56e5494b353 --- /dev/null +++ b/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/java/io/quarkus/virtual/vertx/web/Routes.java @@ -0,0 +1,16 @@ +package io.quarkus.virtual.vertx.web; + +import io.quarkus.vertx.web.Route; +import io.smallrye.common.annotation.RunOnVirtualThread; + +public class Routes { + + @RunOnVirtualThread + @Route + String hello() { + AssertHelper.assertEverything(); + // Quarkus specific - each VT has a unique name + return Thread.currentThread().getName(); + } + +} diff --git a/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/resources/application.properties b/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/resources/application.properties new file mode 100644 index 0000000000000..43b1e230c2184 --- /dev/null +++ b/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/resources/application.properties @@ -0,0 +1,3 @@ +quarkus.native.additional-build-args=--enable-preview + +quarkus.package.quiltflower.enabled=true \ No newline at end of file diff --git a/integration-tests/virtual-threads/scheduler-virtual-threads/src/test/java/io/quarkus/virtual/mail/RunOnVirtualThreadIT.java b/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/test/java/io/quarkus/virtual/vertx/web/RunOnVirtualThreadIT.java similarity index 78% rename from integration-tests/virtual-threads/scheduler-virtual-threads/src/test/java/io/quarkus/virtual/mail/RunOnVirtualThreadIT.java rename to integration-tests/virtual-threads/reactive-routes-virtual-threads/src/test/java/io/quarkus/virtual/vertx/web/RunOnVirtualThreadIT.java index 22abcdce9792e..609672a7779ef 100644 --- a/integration-tests/virtual-threads/scheduler-virtual-threads/src/test/java/io/quarkus/virtual/mail/RunOnVirtualThreadIT.java +++ b/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/test/java/io/quarkus/virtual/vertx/web/RunOnVirtualThreadIT.java @@ -1,4 +1,4 @@ -package io.quarkus.virtual.mail; +package io.quarkus.virtual.vertx.web; import io.quarkus.test.junit.QuarkusIntegrationTest; diff --git a/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/test/java/io/quarkus/virtual/vertx/web/RunOnVirtualThreadTest.java b/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/test/java/io/quarkus/virtual/vertx/web/RunOnVirtualThreadTest.java new file mode 100644 index 0000000000000..041b50df5dc3e --- /dev/null +++ b/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/test/java/io/quarkus/virtual/vertx/web/RunOnVirtualThreadTest.java @@ -0,0 +1,25 @@ +package io.quarkus.virtual.vertx.web; + +import static io.restassured.RestAssured.get; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit5.virtual.ShouldNotPin; +import io.quarkus.test.junit5.virtual.VirtualThreadUnit; + +@QuarkusTest +@VirtualThreadUnit +@ShouldNotPin +class RunOnVirtualThreadTest { + + @Test + void testRoute() { + String bodyStr = get("/hello").then().statusCode(200).extract().asString(); + // Each VT has a unique name in quarkus + assertNotEquals(bodyStr, get("/hello").then().statusCode(200).extract().asString()); + + } + +} diff --git a/integration-tests/virtual-threads/scheduler-virtual-threads/src/test/java/io/quarkus/virtual/scheduler/RunOnVirtualThreadIT.java b/integration-tests/virtual-threads/scheduler-virtual-threads/src/test/java/io/quarkus/virtual/scheduler/RunOnVirtualThreadIT.java new file mode 100644 index 0000000000000..ca669732041a8 --- /dev/null +++ b/integration-tests/virtual-threads/scheduler-virtual-threads/src/test/java/io/quarkus/virtual/scheduler/RunOnVirtualThreadIT.java @@ -0,0 +1,8 @@ +package io.quarkus.virtual.scheduler; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +class RunOnVirtualThreadIT extends RunOnVirtualThreadTest { + +} diff --git a/integration-tests/virtual-threads/scheduler-virtual-threads/src/test/java/io/quarkus/virtual/mail/RunOnVirtualThreadTest.java b/integration-tests/virtual-threads/scheduler-virtual-threads/src/test/java/io/quarkus/virtual/scheduler/RunOnVirtualThreadTest.java similarity index 97% rename from integration-tests/virtual-threads/scheduler-virtual-threads/src/test/java/io/quarkus/virtual/mail/RunOnVirtualThreadTest.java rename to integration-tests/virtual-threads/scheduler-virtual-threads/src/test/java/io/quarkus/virtual/scheduler/RunOnVirtualThreadTest.java index 2a6244806d48b..42ad3e929cf15 100644 --- a/integration-tests/virtual-threads/scheduler-virtual-threads/src/test/java/io/quarkus/virtual/mail/RunOnVirtualThreadTest.java +++ b/integration-tests/virtual-threads/scheduler-virtual-threads/src/test/java/io/quarkus/virtual/scheduler/RunOnVirtualThreadTest.java @@ -1,4 +1,4 @@ -package io.quarkus.virtual.mail; +package io.quarkus.virtual.scheduler; import java.time.Duration; import java.util.List; From 8638dcb6be43f189a1797022a772b3d2cf968efe Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Fri, 13 Oct 2023 10:35:55 +0200 Subject: [PATCH 2/2] Virtual threads: integration tests refactoring - move the logic from AssertHelpers to a shared component - VirtualThreadsAssertions located in quarkus-test-vertx --- .../amqp-virtual-threads/pom.xml | 2 +- .../it/vthreads/amqp/AssertHelper.java | 68 ------------------ .../it/vthreads/amqp/PriceConsumer.java | 16 ++--- .../grpc-virtual-threads/pom.xml | 6 +- .../grpc/example/streaming/AssertHelper.java | 53 -------------- .../example/streaming/TestServiceImpl.java | 19 +++-- .../jms-virtual-threads/pom.xml | 2 +- .../quarkus/it/vthreads/jms/AssertHelper.java | 68 ------------------ .../it/vthreads/jms/PriceConsumer.java | 9 ++- .../kafka-virtual-threads/pom.xml | 3 +- .../it/vthreads/kafka/AssertHelper.java | 68 ------------------ .../it/vthreads/kafka/PriceConsumer.java | 16 ++--- .../mailer-virtual-threads/pom.xml | 6 +- .../io/quarkus/virtual/mail/AssertHelper.java | 71 ------------------- .../quarkus/virtual/mail/MailerResource.java | 5 +- integration-tests/virtual-threads/pom.xml | 4 +- .../quartz-virtual-threads/pom.xml | 6 +- .../virtual/scheduler/AssertHelper.java | 71 ------------------- .../virtual/scheduler/ScheduledResource.java | 5 +- .../reactive-routes-virtual-threads/pom.xml | 5 ++ .../virtual/vertx/web/AssertHelper.java | 71 ------------------- .../io/quarkus/virtual/vertx/web/Routes.java | 16 ++++- .../vertx/web/RunOnVirtualThreadTest.java | 12 +++- .../redis-virtual-threads/pom.xml | 6 +- .../quarkus/virtual/redis/AssertHelper.java | 71 ------------------- .../quarkus/virtual/redis/RedisResource.java | 3 +- .../pom.xml | 6 +- .../io/quarkus/virtual/rest/AssertHelper.java | 71 ------------------- .../virtual/rest/RestClientResource.java | 3 +- .../resteasy-reactive-virtual-threads/pom.xml | 6 +- .../io/quarkus/virtual/rr/AssertHelper.java | 71 ------------------- .../quarkus/virtual/rr/FilteredResource.java | 3 +- .../java/io/quarkus/virtual/rr/Filters.java | 7 +- .../io/quarkus/virtual/rr/MyResource.java | 23 +++--- .../virtual/rr/MyResourceWithVTOnClass.java | 7 +- .../scheduler-virtual-threads/pom.xml | 6 +- .../virtual/scheduler/AssertHelper.java | 71 ------------------- .../virtual/scheduler/ScheduledResource.java | 5 +- .../vertx-event-bus-virtual-threads/pom.xml | 6 +- .../quarkus/virtual/vertx/AssertHelper.java | 71 ------------------- .../virtual/vertx/EventBusConsumer.java | 5 +- .../virtual-threads-disabled/pom.xml | 6 +- .../virtual/disabled/FilteredResource.java | 3 +- .../io/quarkus/virtual/disabled/Filters.java | 7 +- .../quarkus/virtual/disabled/MyResource.java | 19 ++--- .../disabled/MyResourceWithVTOnClass.java | 7 +- .../test/vertx/VirtualThreadsAssertions.java | 4 +- 47 files changed, 160 insertions(+), 929 deletions(-) delete mode 100644 integration-tests/virtual-threads/amqp-virtual-threads/src/main/java/io/quarkus/it/vthreads/amqp/AssertHelper.java delete mode 100644 integration-tests/virtual-threads/grpc-virtual-threads/src/main/java/io/quarkus/grpc/example/streaming/AssertHelper.java delete mode 100644 integration-tests/virtual-threads/jms-virtual-threads/src/main/java/io/quarkus/it/vthreads/jms/AssertHelper.java delete mode 100644 integration-tests/virtual-threads/kafka-virtual-threads/src/main/java/io/quarkus/it/vthreads/kafka/AssertHelper.java delete mode 100644 integration-tests/virtual-threads/mailer-virtual-threads/src/main/java/io/quarkus/virtual/mail/AssertHelper.java delete mode 100644 integration-tests/virtual-threads/quartz-virtual-threads/src/main/java/io/quarkus/virtual/scheduler/AssertHelper.java delete mode 100644 integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/java/io/quarkus/virtual/vertx/web/AssertHelper.java delete mode 100644 integration-tests/virtual-threads/redis-virtual-threads/src/main/java/io/quarkus/virtual/redis/AssertHelper.java delete mode 100644 integration-tests/virtual-threads/rest-client-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rest/AssertHelper.java delete mode 100644 integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/AssertHelper.java delete mode 100644 integration-tests/virtual-threads/scheduler-virtual-threads/src/main/java/io/quarkus/virtual/scheduler/AssertHelper.java delete mode 100644 integration-tests/virtual-threads/vertx-event-bus-virtual-threads/src/main/java/io/quarkus/virtual/vertx/AssertHelper.java rename integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/AssertHelper.java => test-framework/vertx/src/main/java/io/quarkus/test/vertx/VirtualThreadsAssertions.java (97%) diff --git a/integration-tests/virtual-threads/amqp-virtual-threads/pom.xml b/integration-tests/virtual-threads/amqp-virtual-threads/pom.xml index 5e207e911d5b7..6232adfccd4cb 100644 --- a/integration-tests/virtual-threads/amqp-virtual-threads/pom.xml +++ b/integration-tests/virtual-threads/amqp-virtual-threads/pom.xml @@ -52,10 +52,10 @@ assertj-core test + io.quarkus quarkus-test-vertx - test io.quarkus diff --git a/integration-tests/virtual-threads/amqp-virtual-threads/src/main/java/io/quarkus/it/vthreads/amqp/AssertHelper.java b/integration-tests/virtual-threads/amqp-virtual-threads/src/main/java/io/quarkus/it/vthreads/amqp/AssertHelper.java deleted file mode 100644 index cf4317de2b273..0000000000000 --- a/integration-tests/virtual-threads/amqp-virtual-threads/src/main/java/io/quarkus/it/vthreads/amqp/AssertHelper.java +++ /dev/null @@ -1,68 +0,0 @@ -package io.quarkus.it.vthreads.amqp; - -import java.lang.reflect.Method; - -import io.quarkus.arc.Arc; -import io.smallrye.common.vertx.VertxContext; -import io.vertx.core.Vertx; - -public class AssertHelper { - - /** - * Asserts that the current method: - * - runs on a duplicated context - * - runs on a virtual thread - * - has the request scope activated - */ - public static void assertEverything() { - assertThatTheRequestScopeIsActive(); - assertThatItRunsOnVirtualThread(); - assertThatItRunsOnADuplicatedContext(); - } - - public static void assertThatTheRequestScopeIsActive() { - if (!Arc.container().requestContext().isActive()) { - throw new AssertionError(("Expected the request scope to be active")); - } - } - - public static void assertThatItRunsOnADuplicatedContext() { - var context = Vertx.currentContext(); - if (context == null) { - throw new AssertionError("The method does not run on a Vert.x context"); - } - if (!VertxContext.isOnDuplicatedContext()) { - throw new AssertionError("The method does not run on a Vert.x **duplicated** context"); - } - } - - public static void assertThatItRunsOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (!virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is not a virtual thread"); - } - } catch (Exception e) { - throw new AssertionError( - "Thread " + Thread.currentThread() + " is not a virtual thread - cannot invoke Thread.isVirtual()", e); - } - } - - public static void assertThatItDoesNotRunOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is a virtual thread"); - } - } catch (Exception e) { - throw new AssertionError( - "Thread " + Thread.currentThread() + " is a virtual thread - but cannot invoke Thread.isVirtual()", e); - } - } -} diff --git a/integration-tests/virtual-threads/amqp-virtual-threads/src/main/java/io/quarkus/it/vthreads/amqp/PriceConsumer.java b/integration-tests/virtual-threads/amqp-virtual-threads/src/main/java/io/quarkus/it/vthreads/amqp/PriceConsumer.java index 540015bfc892e..3d16daeba6568 100644 --- a/integration-tests/virtual-threads/amqp-virtual-threads/src/main/java/io/quarkus/it/vthreads/amqp/PriceConsumer.java +++ b/integration-tests/virtual-threads/amqp-virtual-threads/src/main/java/io/quarkus/it/vthreads/amqp/PriceConsumer.java @@ -1,8 +1,5 @@ package io.quarkus.it.vthreads.amqp; -import static io.quarkus.it.vthreads.amqp.AssertHelper.assertThatItRunsOnADuplicatedContext; -import static io.quarkus.it.vthreads.amqp.AssertHelper.assertThatItRunsOnVirtualThread; - import java.util.Random; import java.util.concurrent.CompletionStage; import java.util.concurrent.atomic.AtomicInteger; @@ -14,6 +11,7 @@ import org.eclipse.microprofile.reactive.messaging.Outgoing; import org.eclipse.microprofile.rest.client.inject.RestClient; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.smallrye.common.annotation.RunOnVirtualThread; @ApplicationScoped @@ -25,12 +23,12 @@ public class PriceConsumer { @Incoming("prices") @RunOnVirtualThread public CompletionStage consume(Message msg) { - assertThatItRunsOnVirtualThread(); - assertThatItRunsOnADuplicatedContext(); + VirtualThreadsAssertions.assertThatItRunsOnVirtualThread(); + VirtualThreadsAssertions.assertThatItRunsOnADuplicatedContext(); double price = msg.getPayload(); alertService.alertMessage(price); return msg.ack().thenAccept(x -> { - assertThatItRunsOnADuplicatedContext(); + VirtualThreadsAssertions.assertThatItRunsOnADuplicatedContext(); // While the ack always runs on event loop thread // the post-ack may run on the processing virtual-thread which executed the method. }); @@ -39,8 +37,8 @@ public CompletionStage consume(Message msg) { @Incoming("prices") @RunOnVirtualThread public void consume(double price) { - assertThatItRunsOnVirtualThread(); - assertThatItRunsOnADuplicatedContext(); + VirtualThreadsAssertions.assertThatItRunsOnVirtualThread(); + VirtualThreadsAssertions.assertThatItRunsOnADuplicatedContext(); alertService.alert(price); } @@ -50,7 +48,7 @@ public void consume(double price) { @Outgoing("prices-out") @RunOnVirtualThread public Message randomPriceGenerator() { - assertThatItRunsOnVirtualThread(); + VirtualThreadsAssertions.assertThatItRunsOnVirtualThread(); return Message.of(r.nextDouble() * 10 * i.incrementAndGet()); } diff --git a/integration-tests/virtual-threads/grpc-virtual-threads/pom.xml b/integration-tests/virtual-threads/grpc-virtual-threads/pom.xml index ba8052cf73552..c2bc0a8630f37 100644 --- a/integration-tests/virtual-threads/grpc-virtual-threads/pom.xml +++ b/integration-tests/virtual-threads/grpc-virtual-threads/pom.xml @@ -22,7 +22,11 @@ io.quarkus quarkus-grpc - + + + io.quarkus + quarkus-test-vertx + io.quarkus quarkus-junit5 diff --git a/integration-tests/virtual-threads/grpc-virtual-threads/src/main/java/io/quarkus/grpc/example/streaming/AssertHelper.java b/integration-tests/virtual-threads/grpc-virtual-threads/src/main/java/io/quarkus/grpc/example/streaming/AssertHelper.java deleted file mode 100644 index 4b45668d60c24..0000000000000 --- a/integration-tests/virtual-threads/grpc-virtual-threads/src/main/java/io/quarkus/grpc/example/streaming/AssertHelper.java +++ /dev/null @@ -1,53 +0,0 @@ -package io.quarkus.grpc.example.streaming; - -import java.lang.reflect.Method; - -import io.quarkus.arc.Arc; -import io.smallrye.common.vertx.VertxContext; -import io.vertx.core.Vertx; - -public class AssertHelper { - - /** - * Asserts that the current method: - * - runs on a duplicated context - * - runs on a virtual thread - * - has the request scope activated - */ - public static void assertEverything() { - assertThatTheRequestScopeIsActive(); - assertThatItRunsOnVirtualThread(); - assertThatItRunsOnADuplicatedContext(); - } - - public static void assertThatTheRequestScopeIsActive() { - if (!Arc.container().requestContext().isActive()) { - throw new AssertionError(("Expected the request scope to be active")); - } - } - - public static void assertThatItRunsOnADuplicatedContext() { - var context = Vertx.currentContext(); - if (context == null) { - throw new AssertionError("The method does not run on a Vert.x context"); - } - if (!VertxContext.isOnDuplicatedContext()) { - throw new AssertionError("The method does not run on a Vert.x **duplicated** context"); - } - } - - public static void assertThatItRunsOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (!virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is not a virtual thread"); - } - } catch (Exception e) { - throw new AssertionError( - "Thread " + Thread.currentThread() + " is not a virtual thread - cannot invoke Thread.isVirtual()", e); - } - } -} diff --git a/integration-tests/virtual-threads/grpc-virtual-threads/src/main/java/io/quarkus/grpc/example/streaming/TestServiceImpl.java b/integration-tests/virtual-threads/grpc-virtual-threads/src/main/java/io/quarkus/grpc/example/streaming/TestServiceImpl.java index 40f3f2fcdb14d..f721185b5a700 100644 --- a/integration-tests/virtual-threads/grpc-virtual-threads/src/main/java/io/quarkus/grpc/example/streaming/TestServiceImpl.java +++ b/integration-tests/virtual-threads/grpc-virtual-threads/src/main/java/io/quarkus/grpc/example/streaming/TestServiceImpl.java @@ -1,13 +1,12 @@ package io.quarkus.grpc.example.streaming; -import static io.quarkus.grpc.example.streaming.AssertHelper.assertEverything; - import com.google.protobuf.ByteString; import com.google.protobuf.EmptyProtos; import io.grpc.testing.integration.Messages; import io.grpc.testing.integration.TestService; import io.quarkus.grpc.GrpcService; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.smallrye.common.annotation.RunOnVirtualThread; import io.smallrye.mutiny.Multi; import io.smallrye.mutiny.Uni; @@ -18,30 +17,30 @@ public class TestServiceImpl implements TestService { @RunOnVirtualThread @Override public Uni emptyCall(EmptyProtos.Empty request) { - assertEverything(); + VirtualThreadsAssertions.assertEverything(); return Uni.createFrom().item(EmptyProtos.Empty.newBuilder().build()) - .invoke(AssertHelper::assertEverything); + .invoke(VirtualThreadsAssertions::assertEverything); } @RunOnVirtualThread @Override public Uni unaryCall(Messages.SimpleRequest request) { - assertEverything(); + VirtualThreadsAssertions.assertEverything(); var value = request.getPayload().getBody().toStringUtf8(); var resp = Messages.SimpleResponse.newBuilder() .setPayload(Messages.Payload.newBuilder().setBody(ByteString.copyFromUtf8(value.toUpperCase())).build()) .build(); return Uni.createFrom().item(resp) - .invoke(AssertHelper::assertEverything); + .invoke(VirtualThreadsAssertions::assertEverything); } @Override @RunOnVirtualThread public Multi streamingOutputCall(Messages.StreamingOutputCallRequest request) { var value = request.getPayload().getBody().toStringUtf8(); - assertEverything(); + VirtualThreadsAssertions.assertEverything(); return Multi.createFrom(). emitter(emitter -> { - assertEverything(); + VirtualThreadsAssertions.assertEverything(); emitter.emit(value.toUpperCase()); emitter.emit(value.toUpperCase()); emitter.emit(value.toUpperCase()); @@ -49,8 +48,8 @@ public Multi streamingOutputCall(Messages. }).map(v -> Messages.StreamingOutputCallResponse.newBuilder() .setPayload(Messages.Payload.newBuilder().setBody(ByteString.copyFromUtf8(v)).build()) .build()) - .invoke(AssertHelper::assertEverything) - .onTermination().invoke(AssertHelper::assertEverything); + .invoke(VirtualThreadsAssertions::assertEverything) + .onTermination().invoke(VirtualThreadsAssertions::assertEverything); } } diff --git a/integration-tests/virtual-threads/jms-virtual-threads/pom.xml b/integration-tests/virtual-threads/jms-virtual-threads/pom.xml index 2c52d9aaa85b5..90a6fb2f80a08 100644 --- a/integration-tests/virtual-threads/jms-virtual-threads/pom.xml +++ b/integration-tests/virtual-threads/jms-virtual-threads/pom.xml @@ -78,10 +78,10 @@ assertj-core test + io.quarkus quarkus-test-vertx - test io.quarkus diff --git a/integration-tests/virtual-threads/jms-virtual-threads/src/main/java/io/quarkus/it/vthreads/jms/AssertHelper.java b/integration-tests/virtual-threads/jms-virtual-threads/src/main/java/io/quarkus/it/vthreads/jms/AssertHelper.java deleted file mode 100644 index 1f1c0ad2965dd..0000000000000 --- a/integration-tests/virtual-threads/jms-virtual-threads/src/main/java/io/quarkus/it/vthreads/jms/AssertHelper.java +++ /dev/null @@ -1,68 +0,0 @@ -package io.quarkus.it.vthreads.jms; - -import java.lang.reflect.Method; - -import io.quarkus.arc.Arc; -import io.smallrye.common.vertx.VertxContext; -import io.vertx.core.Vertx; - -public class AssertHelper { - - /** - * Asserts that the current method: - * - runs on a duplicated context - * - runs on a virtual thread - * - has the request scope activated - */ - public static void assertEverything() { - assertThatTheRequestScopeIsActive(); - assertThatItRunsOnVirtualThread(); - assertThatItRunsOnADuplicatedContext(); - } - - public static void assertThatTheRequestScopeIsActive() { - if (!Arc.container().requestContext().isActive()) { - throw new AssertionError(("Expected the request scope to be active")); - } - } - - public static void assertThatItRunsOnADuplicatedContext() { - var context = Vertx.currentContext(); - if (context == null) { - throw new AssertionError("The method does not run on a Vert.x context"); - } - if (!VertxContext.isOnDuplicatedContext()) { - throw new AssertionError("The method does not run on a Vert.x **duplicated** context"); - } - } - - public static void assertThatItRunsOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (!virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is not a virtual thread"); - } - } catch (Exception e) { - throw new AssertionError( - "Thread " + Thread.currentThread() + " is not a virtual thread - cannot invoke Thread.isVirtual()", e); - } - } - - public static void assertThatItDoesNotRunOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is a virtual thread"); - } - } catch (Exception e) { - throw new AssertionError( - "Thread " + Thread.currentThread() + " is a virtual thread - but cannot invoke Thread.isVirtual()", e); - } - } -} diff --git a/integration-tests/virtual-threads/jms-virtual-threads/src/main/java/io/quarkus/it/vthreads/jms/PriceConsumer.java b/integration-tests/virtual-threads/jms-virtual-threads/src/main/java/io/quarkus/it/vthreads/jms/PriceConsumer.java index b74f7dfd7baec..3547e4890d6d9 100644 --- a/integration-tests/virtual-threads/jms-virtual-threads/src/main/java/io/quarkus/it/vthreads/jms/PriceConsumer.java +++ b/integration-tests/virtual-threads/jms-virtual-threads/src/main/java/io/quarkus/it/vthreads/jms/PriceConsumer.java @@ -1,7 +1,5 @@ package io.quarkus.it.vthreads.jms; -import static io.quarkus.it.vthreads.jms.AssertHelper.assertThatItRunsOnVirtualThread; - import java.util.Random; import java.util.concurrent.CompletionStage; import java.util.concurrent.atomic.AtomicInteger; @@ -13,6 +11,7 @@ import org.eclipse.microprofile.reactive.messaging.Outgoing; import org.eclipse.microprofile.rest.client.inject.RestClient; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.smallrye.common.annotation.RunOnVirtualThread; @ApplicationScoped @@ -24,7 +23,7 @@ public class PriceConsumer { @Incoming("prices") @RunOnVirtualThread public CompletionStage consume(Message msg) { - assertThatItRunsOnVirtualThread(); + VirtualThreadsAssertions.assertThatItRunsOnVirtualThread(); double price = msg.getPayload(); alertService.alertMessage(price); return msg.ack(); @@ -33,7 +32,7 @@ public CompletionStage consume(Message msg) { @Incoming("prices") @RunOnVirtualThread public void consume(double price) { - assertThatItRunsOnVirtualThread(); + VirtualThreadsAssertions.assertThatItRunsOnVirtualThread(); alertService.alert(price); } @@ -43,7 +42,7 @@ public void consume(double price) { @Outgoing("prices-out") @RunOnVirtualThread public Message randomPriceGenerator() { - assertThatItRunsOnVirtualThread(); + VirtualThreadsAssertions.assertThatItRunsOnVirtualThread(); return Message.of(r.nextDouble() * 10 * i.incrementAndGet()); } diff --git a/integration-tests/virtual-threads/kafka-virtual-threads/pom.xml b/integration-tests/virtual-threads/kafka-virtual-threads/pom.xml index 16c86a83ad846..0c0706d3c21bb 100644 --- a/integration-tests/virtual-threads/kafka-virtual-threads/pom.xml +++ b/integration-tests/virtual-threads/kafka-virtual-threads/pom.xml @@ -26,7 +26,6 @@ io.quarkus quarkus-rest-client-reactive - io.quarkus quarkus-junit5 @@ -52,10 +51,10 @@ assertj-core test + io.quarkus quarkus-test-vertx - test io.quarkus diff --git a/integration-tests/virtual-threads/kafka-virtual-threads/src/main/java/io/quarkus/it/vthreads/kafka/AssertHelper.java b/integration-tests/virtual-threads/kafka-virtual-threads/src/main/java/io/quarkus/it/vthreads/kafka/AssertHelper.java deleted file mode 100644 index 35299e5918b7c..0000000000000 --- a/integration-tests/virtual-threads/kafka-virtual-threads/src/main/java/io/quarkus/it/vthreads/kafka/AssertHelper.java +++ /dev/null @@ -1,68 +0,0 @@ -package io.quarkus.it.vthreads.kafka; - -import java.lang.reflect.Method; - -import io.quarkus.arc.Arc; -import io.smallrye.common.vertx.VertxContext; -import io.vertx.core.Vertx; - -public class AssertHelper { - - /** - * Asserts that the current method: - * - runs on a duplicated context - * - runs on a virtual thread - * - has the request scope activated - */ - public static void assertEverything() { - assertThatTheRequestScopeIsActive(); - assertThatItRunsOnVirtualThread(); - assertThatItRunsOnADuplicatedContext(); - } - - public static void assertThatTheRequestScopeIsActive() { - if (!Arc.container().requestContext().isActive()) { - throw new AssertionError(("Expected the request scope to be active")); - } - } - - public static void assertThatItRunsOnADuplicatedContext() { - var context = Vertx.currentContext(); - if (context == null) { - throw new AssertionError("The method does not run on a Vert.x context"); - } - if (!VertxContext.isOnDuplicatedContext()) { - throw new AssertionError("The method does not run on a Vert.x **duplicated** context"); - } - } - - public static void assertThatItRunsOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (!virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is not a virtual thread"); - } - } catch (Exception e) { - throw new AssertionError( - "Thread " + Thread.currentThread() + " is not a virtual thread - cannot invoke Thread.isVirtual()", e); - } - } - - public static void assertThatItDoesNotRunOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is a virtual thread"); - } - } catch (Exception e) { - throw new AssertionError( - "Thread " + Thread.currentThread() + " is a virtual thread - but cannot invoke Thread.isVirtual()", e); - } - } -} diff --git a/integration-tests/virtual-threads/kafka-virtual-threads/src/main/java/io/quarkus/it/vthreads/kafka/PriceConsumer.java b/integration-tests/virtual-threads/kafka-virtual-threads/src/main/java/io/quarkus/it/vthreads/kafka/PriceConsumer.java index f305a3a5f86fc..cbd9f1537621c 100644 --- a/integration-tests/virtual-threads/kafka-virtual-threads/src/main/java/io/quarkus/it/vthreads/kafka/PriceConsumer.java +++ b/integration-tests/virtual-threads/kafka-virtual-threads/src/main/java/io/quarkus/it/vthreads/kafka/PriceConsumer.java @@ -1,8 +1,5 @@ package io.quarkus.it.vthreads.kafka; -import static io.quarkus.it.vthreads.kafka.AssertHelper.assertThatItRunsOnADuplicatedContext; -import static io.quarkus.it.vthreads.kafka.AssertHelper.assertThatItRunsOnVirtualThread; - import java.util.Random; import java.util.concurrent.CompletionStage; import java.util.concurrent.atomic.AtomicInteger; @@ -14,6 +11,7 @@ import org.eclipse.microprofile.reactive.messaging.Outgoing; import org.eclipse.microprofile.rest.client.inject.RestClient; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.smallrye.common.annotation.RunOnVirtualThread; @ApplicationScoped @@ -25,12 +23,12 @@ public class PriceConsumer { @Incoming("prices") @RunOnVirtualThread public CompletionStage consume(Message msg) { - assertThatItRunsOnVirtualThread(); - assertThatItRunsOnADuplicatedContext(); + VirtualThreadsAssertions.assertThatItRunsOnVirtualThread(); + VirtualThreadsAssertions.assertThatItRunsOnADuplicatedContext(); double price = msg.getPayload(); alertService.alertMessage(price); return msg.ack().thenAccept(x -> { - assertThatItRunsOnADuplicatedContext(); + VirtualThreadsAssertions.assertThatItRunsOnADuplicatedContext(); // While the ack always runs on event loop thread // the post-ack may run on the processing virtual-thread which executed the method. }); @@ -39,8 +37,8 @@ public CompletionStage consume(Message msg) { @Incoming("prices") @RunOnVirtualThread public void consume(double price) { - assertThatItRunsOnVirtualThread(); - assertThatItRunsOnADuplicatedContext(); + VirtualThreadsAssertions.assertThatItRunsOnVirtualThread(); + VirtualThreadsAssertions.assertThatItRunsOnADuplicatedContext(); alertService.alert(price); } @@ -50,7 +48,7 @@ public void consume(double price) { @Outgoing("prices-out") @RunOnVirtualThread public Message randomPriceGenerator() { - assertThatItRunsOnVirtualThread(); + VirtualThreadsAssertions.assertThatItRunsOnVirtualThread(); return Message.of(r.nextDouble() * 10 * i.incrementAndGet()); } diff --git a/integration-tests/virtual-threads/mailer-virtual-threads/pom.xml b/integration-tests/virtual-threads/mailer-virtual-threads/pom.xml index 9ed5f6e17c566..0dd47653079e7 100644 --- a/integration-tests/virtual-threads/mailer-virtual-threads/pom.xml +++ b/integration-tests/virtual-threads/mailer-virtual-threads/pom.xml @@ -22,7 +22,11 @@ io.quarkus quarkus-mailer - + + + io.quarkus + quarkus-test-vertx + io.quarkus quarkus-junit5 diff --git a/integration-tests/virtual-threads/mailer-virtual-threads/src/main/java/io/quarkus/virtual/mail/AssertHelper.java b/integration-tests/virtual-threads/mailer-virtual-threads/src/main/java/io/quarkus/virtual/mail/AssertHelper.java deleted file mode 100644 index d89a517af7ec8..0000000000000 --- a/integration-tests/virtual-threads/mailer-virtual-threads/src/main/java/io/quarkus/virtual/mail/AssertHelper.java +++ /dev/null @@ -1,71 +0,0 @@ -package io.quarkus.virtual.mail; - -import java.lang.reflect.Method; - -import io.quarkus.arc.Arc; -import io.smallrye.common.vertx.VertxContext; -import io.vertx.core.Vertx; - -public class AssertHelper { - - /** - * Asserts that the current method: - * - runs on a duplicated context - * - runs on a virtual thread - * - has the request scope activated - */ - public static void assertEverything() { - assertThatTheRequestScopeIsActive(); - assertThatItRunsOnVirtualThread(); - assertThatItRunsOnADuplicatedContext(); - } - - public static void assertThatTheRequestScopeIsActive() { - if (!Arc.container().requestContext().isActive()) { - throw new AssertionError(("Expected the request scope to be active")); - } - } - - public static void assertThatItRunsOnADuplicatedContext() { - var context = Vertx.currentContext(); - if (context == null) { - throw new AssertionError("The method does not run on a Vert.x context"); - } - if (!VertxContext.isOnDuplicatedContext()) { - throw new AssertionError("The method does not run on a Vert.x **duplicated** context"); - } - } - - public static void assertThatItRunsOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (!virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is not a virtual thread"); - } - } catch (Exception e) { - throw new AssertionError( - "Thread " + Thread.currentThread() + " is not a virtual thread - cannot invoke Thread.isVirtual()", e); - } - } - - public static void assertNotOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is a virtual thread"); - } - } catch (Exception e) { - // Trying using Thread name. - var name = Thread.currentThread().toString(); - if (name.toLowerCase().contains("virtual")) { - throw new AssertionError("Thread " + Thread.currentThread() + " seems to be a virtual thread"); - } - } - } -} diff --git a/integration-tests/virtual-threads/mailer-virtual-threads/src/main/java/io/quarkus/virtual/mail/MailerResource.java b/integration-tests/virtual-threads/mailer-virtual-threads/src/main/java/io/quarkus/virtual/mail/MailerResource.java index 83ab7da484334..2ae94477e6bcd 100644 --- a/integration-tests/virtual-threads/mailer-virtual-threads/src/main/java/io/quarkus/virtual/mail/MailerResource.java +++ b/integration-tests/virtual-threads/mailer-virtual-threads/src/main/java/io/quarkus/virtual/mail/MailerResource.java @@ -10,6 +10,7 @@ import io.quarkus.mailer.MailTemplate; import io.quarkus.mailer.Mailer; import io.quarkus.qute.CheckedTemplate; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.smallrye.common.annotation.RunOnVirtualThread; @Path("/") @@ -21,7 +22,7 @@ public class MailerResource { @GET public String send() { - AssertHelper.assertEverything(); + VirtualThreadsAssertions.assertEverything(); mailer.send(Mail.withText("roger-the-robot@quarkus.io", "test simple", "This email is sent from a virtual thread")); return "OK"; } @@ -29,7 +30,7 @@ public String send() { @GET @Path("/template") public String sendWithTemplate() { - AssertHelper.assertEverything(); + VirtualThreadsAssertions.assertEverything(); Templates.hello("virtual threads").to("roger-the-robot@quarkus.io").subject("test template").send().await() .atMost(Duration.ofSeconds(3)); return "OK"; diff --git a/integration-tests/virtual-threads/pom.xml b/integration-tests/virtual-threads/pom.xml index e348c119ee410..f23f86a062baa 100644 --- a/integration-tests/virtual-threads/pom.xml +++ b/integration-tests/virtual-threads/pom.xml @@ -35,8 +35,8 @@ vertx-event-bus-virtual-threads scheduler-virtual-threads quartz-virtual-threads - virtual-threads-disabled - reactive-routes-virtual-threads + virtual-threads-disabled + reactive-routes-virtual-threads diff --git a/integration-tests/virtual-threads/quartz-virtual-threads/pom.xml b/integration-tests/virtual-threads/quartz-virtual-threads/pom.xml index 77a37c7b6e55b..48a7f81ce3080 100644 --- a/integration-tests/virtual-threads/quartz-virtual-threads/pom.xml +++ b/integration-tests/virtual-threads/quartz-virtual-threads/pom.xml @@ -22,7 +22,11 @@ io.quarkus quarkus-quartz - + + + io.quarkus + quarkus-test-vertx + io.quarkus quarkus-junit5 diff --git a/integration-tests/virtual-threads/quartz-virtual-threads/src/main/java/io/quarkus/virtual/scheduler/AssertHelper.java b/integration-tests/virtual-threads/quartz-virtual-threads/src/main/java/io/quarkus/virtual/scheduler/AssertHelper.java deleted file mode 100644 index c967414c5b3f8..0000000000000 --- a/integration-tests/virtual-threads/quartz-virtual-threads/src/main/java/io/quarkus/virtual/scheduler/AssertHelper.java +++ /dev/null @@ -1,71 +0,0 @@ -package io.quarkus.virtual.scheduler; - -import java.lang.reflect.Method; - -import io.quarkus.arc.Arc; -import io.smallrye.common.vertx.VertxContext; -import io.vertx.core.Vertx; - -public class AssertHelper { - - /** - * Asserts that the current method: - * - runs on a duplicated context - * - runs on a virtual thread - * - has the request scope activated - */ - public static void assertEverything() { - assertThatTheRequestScopeIsActive(); - assertThatItRunsOnVirtualThread(); - assertThatItRunsOnADuplicatedContext(); - } - - public static void assertThatTheRequestScopeIsActive() { - if (!Arc.container().requestContext().isActive()) { - throw new AssertionError(("Expected the request scope to be active")); - } - } - - public static void assertThatItRunsOnADuplicatedContext() { - var context = Vertx.currentContext(); - if (context == null) { - throw new AssertionError("The method does not run on a Vert.x context"); - } - if (!VertxContext.isOnDuplicatedContext()) { - throw new AssertionError("The method does not run on a Vert.x **duplicated** context"); - } - } - - public static void assertThatItRunsOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (!virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is not a virtual thread"); - } - } catch (Exception e) { - throw new AssertionError( - "Thread " + Thread.currentThread() + " is not a virtual thread - cannot invoke Thread.isVirtual()", e); - } - } - - public static void assertNotOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is a virtual thread"); - } - } catch (Exception e) { - // Trying using Thread name. - var name = Thread.currentThread().toString(); - if (name.toLowerCase().contains("virtual")) { - throw new AssertionError("Thread " + Thread.currentThread() + " seems to be a virtual thread"); - } - } - } -} diff --git a/integration-tests/virtual-threads/quartz-virtual-threads/src/main/java/io/quarkus/virtual/scheduler/ScheduledResource.java b/integration-tests/virtual-threads/quartz-virtual-threads/src/main/java/io/quarkus/virtual/scheduler/ScheduledResource.java index 0b4588c16dbfb..143fcf34c1a09 100644 --- a/integration-tests/virtual-threads/quartz-virtual-threads/src/main/java/io/quarkus/virtual/scheduler/ScheduledResource.java +++ b/integration-tests/virtual-threads/quartz-virtual-threads/src/main/java/io/quarkus/virtual/scheduler/ScheduledResource.java @@ -10,6 +10,7 @@ import io.quarkus.runtime.StartupEvent; import io.quarkus.scheduler.Scheduled; import io.quarkus.scheduler.Scheduler; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.smallrye.common.annotation.RunOnVirtualThread; @Path("/") @@ -22,7 +23,7 @@ public void init(@Observes StartupEvent ev, Scheduler scheduler) { scheduler.newJob("my-programmatic-job") .setInterval("1s") .setTask(ex -> { - AssertHelper.assertEverything(); + VirtualThreadsAssertions.assertEverything(); // Quarkus specific - each VT has a unique name programmaticExecutions.add(Thread.currentThread().getName()); }, true) @@ -32,7 +33,7 @@ public void init(@Observes StartupEvent ev, Scheduler scheduler) { @Scheduled(every = "1s") @RunOnVirtualThread void run() { - AssertHelper.assertEverything(); + VirtualThreadsAssertions.assertEverything(); // Quarkus specific - each VT has a unique name executions.add(Thread.currentThread().getName()); } diff --git a/integration-tests/virtual-threads/reactive-routes-virtual-threads/pom.xml b/integration-tests/virtual-threads/reactive-routes-virtual-threads/pom.xml index e1b096a0c4cff..b3f982c157707 100644 --- a/integration-tests/virtual-threads/reactive-routes-virtual-threads/pom.xml +++ b/integration-tests/virtual-threads/reactive-routes-virtual-threads/pom.xml @@ -18,6 +18,11 @@ io.quarkus quarkus-reactive-routes + + + io.quarkus + quarkus-test-vertx + io.quarkus quarkus-junit5 diff --git a/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/java/io/quarkus/virtual/vertx/web/AssertHelper.java b/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/java/io/quarkus/virtual/vertx/web/AssertHelper.java deleted file mode 100644 index a96082b02791e..0000000000000 --- a/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/java/io/quarkus/virtual/vertx/web/AssertHelper.java +++ /dev/null @@ -1,71 +0,0 @@ -package io.quarkus.virtual.vertx.web; - -import java.lang.reflect.Method; - -import io.quarkus.arc.Arc; -import io.smallrye.common.vertx.VertxContext; -import io.vertx.core.Vertx; - -public class AssertHelper { - - /** - * Asserts that the current method: - * - runs on a duplicated context - * - runs on a virtual thread - * - has the request scope activated - */ - public static void assertEverything() { - assertThatTheRequestScopeIsActive(); - assertThatItRunsOnVirtualThread(); - assertThatItRunsOnADuplicatedContext(); - } - - public static void assertThatTheRequestScopeIsActive() { - if (!Arc.container().requestContext().isActive()) { - throw new AssertionError(("Expected the request scope to be active")); - } - } - - public static void assertThatItRunsOnADuplicatedContext() { - var context = Vertx.currentContext(); - if (context == null) { - throw new AssertionError("The method does not run on a Vert.x context"); - } - if (!VertxContext.isOnDuplicatedContext()) { - throw new AssertionError("The method does not run on a Vert.x **duplicated** context"); - } - } - - public static void assertThatItRunsOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (!virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is not a virtual thread"); - } - } catch (Exception e) { - throw new AssertionError( - "Thread " + Thread.currentThread() + " is not a virtual thread - cannot invoke Thread.isVirtual()", e); - } - } - - public static void assertNotOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is a virtual thread"); - } - } catch (Exception e) { - // Trying using Thread name. - var name = Thread.currentThread().toString(); - if (name.toLowerCase().contains("virtual")) { - throw new AssertionError("Thread " + Thread.currentThread() + " seems to be a virtual thread"); - } - } - } -} diff --git a/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/java/io/quarkus/virtual/vertx/web/Routes.java b/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/java/io/quarkus/virtual/vertx/web/Routes.java index 6e56e5494b353..f9c86e1ffcf06 100644 --- a/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/java/io/quarkus/virtual/vertx/web/Routes.java +++ b/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/main/java/io/quarkus/virtual/vertx/web/Routes.java @@ -1,6 +1,8 @@ package io.quarkus.virtual.vertx.web; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.quarkus.vertx.web.Route; +import io.smallrye.common.annotation.Blocking; import io.smallrye.common.annotation.RunOnVirtualThread; public class Routes { @@ -8,9 +10,21 @@ public class Routes { @RunOnVirtualThread @Route String hello() { - AssertHelper.assertEverything(); + VirtualThreadsAssertions.assertEverything(); // Quarkus specific - each VT has a unique name return Thread.currentThread().getName(); } + @Route + String ping() { + VirtualThreadsAssertions.assertWorkerOrEventLoopThread(); + return "pong"; + } + + @Blocking + @Route + String blockingPing() { + return ping(); + } + } diff --git a/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/test/java/io/quarkus/virtual/vertx/web/RunOnVirtualThreadTest.java b/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/test/java/io/quarkus/virtual/vertx/web/RunOnVirtualThreadTest.java index 041b50df5dc3e..9175d7536ca71 100644 --- a/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/test/java/io/quarkus/virtual/vertx/web/RunOnVirtualThreadTest.java +++ b/integration-tests/virtual-threads/reactive-routes-virtual-threads/src/test/java/io/quarkus/virtual/vertx/web/RunOnVirtualThreadTest.java @@ -1,6 +1,7 @@ package io.quarkus.virtual.vertx.web; import static io.restassured.RestAssured.get; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import org.junit.jupiter.api.Test; @@ -15,11 +16,20 @@ class RunOnVirtualThreadTest { @Test - void testRoute() { + void testRouteOnVirtualThread() { String bodyStr = get("/hello").then().statusCode(200).extract().asString(); // Each VT has a unique name in quarkus assertNotEquals(bodyStr, get("/hello").then().statusCode(200).extract().asString()); + } + @Test + void testRouteOnEventLoop() { + assertEquals("pong", get("/ping").then().statusCode(200).extract().asString()); + } + + @Test + void testRouteOnWorker() { + assertEquals("pong", get("/blocking-ping").then().statusCode(200).extract().asString()); } } diff --git a/integration-tests/virtual-threads/redis-virtual-threads/pom.xml b/integration-tests/virtual-threads/redis-virtual-threads/pom.xml index 9b333098d0d45..c003f44251f85 100644 --- a/integration-tests/virtual-threads/redis-virtual-threads/pom.xml +++ b/integration-tests/virtual-threads/redis-virtual-threads/pom.xml @@ -26,7 +26,11 @@ io.quarkus quarkus-redis-client - + + + io.quarkus + quarkus-test-vertx + io.quarkus quarkus-junit5 diff --git a/integration-tests/virtual-threads/redis-virtual-threads/src/main/java/io/quarkus/virtual/redis/AssertHelper.java b/integration-tests/virtual-threads/redis-virtual-threads/src/main/java/io/quarkus/virtual/redis/AssertHelper.java deleted file mode 100644 index f58f5d7a63ada..0000000000000 --- a/integration-tests/virtual-threads/redis-virtual-threads/src/main/java/io/quarkus/virtual/redis/AssertHelper.java +++ /dev/null @@ -1,71 +0,0 @@ -package io.quarkus.virtual.redis; - -import java.lang.reflect.Method; - -import io.quarkus.arc.Arc; -import io.smallrye.common.vertx.VertxContext; -import io.vertx.core.Vertx; - -public class AssertHelper { - - /** - * Asserts that the current method: - * - runs on a duplicated context - * - runs on a virtual thread - * - has the request scope activated - */ - public static void assertEverything() { - assertThatTheRequestScopeIsActive(); - assertThatItRunsOnVirtualThread(); - assertThatItRunsOnADuplicatedContext(); - } - - public static void assertThatTheRequestScopeIsActive() { - if (!Arc.container().requestContext().isActive()) { - throw new AssertionError(("Expected the request scope to be active")); - } - } - - public static void assertThatItRunsOnADuplicatedContext() { - var context = Vertx.currentContext(); - if (context == null) { - throw new AssertionError("The method does not run on a Vert.x context"); - } - if (!VertxContext.isOnDuplicatedContext()) { - throw new AssertionError("The method does not run on a Vert.x **duplicated** context"); - } - } - - public static void assertThatItRunsOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (!virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is not a virtual thread"); - } - } catch (Exception e) { - throw new AssertionError( - "Thread " + Thread.currentThread() + " is not a virtual thread - cannot invoke Thread.isVirtual()", e); - } - } - - public static void assertNotOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is a virtual thread"); - } - } catch (Exception e) { - // Trying using Thread name. - var name = Thread.currentThread().toString(); - if (name.toLowerCase().contains("virtual")) { - throw new AssertionError("Thread " + Thread.currentThread() + " seems to be a virtual thread"); - } - } - } -} diff --git a/integration-tests/virtual-threads/redis-virtual-threads/src/main/java/io/quarkus/virtual/redis/RedisResource.java b/integration-tests/virtual-threads/redis-virtual-threads/src/main/java/io/quarkus/virtual/redis/RedisResource.java index 998951142a742..6326046280546 100644 --- a/integration-tests/virtual-threads/redis-virtual-threads/src/main/java/io/quarkus/virtual/redis/RedisResource.java +++ b/integration-tests/virtual-threads/redis-virtual-threads/src/main/java/io/quarkus/virtual/redis/RedisResource.java @@ -8,6 +8,7 @@ import io.quarkus.cache.CacheResult; import io.quarkus.redis.datasource.RedisDataSource; import io.quarkus.redis.datasource.hash.HashCommands; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.smallrye.common.annotation.RunOnVirtualThread; @Path("/") @@ -22,7 +23,7 @@ public RedisResource(RedisDataSource ds) { @GET public String testRedis() { - AssertHelper.assertEverything(); + VirtualThreadsAssertions.assertEverything(); String value = UUID.randomUUID().toString(); hash.hset("test", "test", value); diff --git a/integration-tests/virtual-threads/rest-client-reactive-virtual-threads/pom.xml b/integration-tests/virtual-threads/rest-client-reactive-virtual-threads/pom.xml index d5a26f855ea21..98467ae471ecd 100644 --- a/integration-tests/virtual-threads/rest-client-reactive-virtual-threads/pom.xml +++ b/integration-tests/virtual-threads/rest-client-reactive-virtual-threads/pom.xml @@ -22,7 +22,11 @@ io.quarkus quarkus-rest-client-reactive-jackson - + + + io.quarkus + quarkus-test-vertx + io.quarkus quarkus-junit5 diff --git a/integration-tests/virtual-threads/rest-client-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rest/AssertHelper.java b/integration-tests/virtual-threads/rest-client-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rest/AssertHelper.java deleted file mode 100644 index 9d9d971e41b93..0000000000000 --- a/integration-tests/virtual-threads/rest-client-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rest/AssertHelper.java +++ /dev/null @@ -1,71 +0,0 @@ -package io.quarkus.virtual.rest; - -import java.lang.reflect.Method; - -import io.quarkus.arc.Arc; -import io.smallrye.common.vertx.VertxContext; -import io.vertx.core.Vertx; - -public class AssertHelper { - - /** - * Asserts that the current method: - * - runs on a duplicated context - * - runs on a virtual thread - * - has the request scope activated - */ - public static void assertEverything() { - assertThatTheRequestScopeIsActive(); - assertThatItRunsOnVirtualThread(); - assertThatItRunsOnADuplicatedContext(); - } - - public static void assertThatTheRequestScopeIsActive() { - if (!Arc.container().requestContext().isActive()) { - throw new AssertionError(("Expected the request scope to be active")); - } - } - - public static void assertThatItRunsOnADuplicatedContext() { - var context = Vertx.currentContext(); - if (context == null) { - throw new AssertionError("The method does not run on a Vert.x context"); - } - if (!VertxContext.isOnDuplicatedContext()) { - throw new AssertionError("The method does not run on a Vert.x **duplicated** context"); - } - } - - public static void assertThatItRunsOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (!virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is not a virtual thread"); - } - } catch (Exception e) { - throw new AssertionError( - "Thread " + Thread.currentThread() + " is not a virtual thread - cannot invoke Thread.isVirtual()", e); - } - } - - public static void assertNotOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is a virtual thread"); - } - } catch (Exception e) { - // Trying using Thread name. - var name = Thread.currentThread().toString(); - if (name.toLowerCase().contains("virtual")) { - throw new AssertionError("Thread " + Thread.currentThread() + " seems to be a virtual thread"); - } - } - } -} diff --git a/integration-tests/virtual-threads/rest-client-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rest/RestClientResource.java b/integration-tests/virtual-threads/rest-client-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rest/RestClientResource.java index 04658da72be13..3999e24058263 100644 --- a/integration-tests/virtual-threads/rest-client-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rest/RestClientResource.java +++ b/integration-tests/virtual-threads/rest-client-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rest/RestClientResource.java @@ -5,6 +5,7 @@ import org.eclipse.microprofile.rest.client.inject.RestClient; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.smallrye.common.annotation.RunOnVirtualThread; @Path("/") @@ -16,7 +17,7 @@ public class RestClientResource { @GET public Greeting test() { - AssertHelper.assertEverything(); + VirtualThreadsAssertions.assertEverything(); return client.hello(); } diff --git a/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/pom.xml b/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/pom.xml index f59e520c0348e..80c92d4de9802 100644 --- a/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/pom.xml +++ b/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/pom.xml @@ -18,7 +18,11 @@ io.quarkus quarkus-resteasy-reactive-jackson - + + + io.quarkus + quarkus-test-vertx + io.quarkus quarkus-junit5 diff --git a/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/AssertHelper.java b/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/AssertHelper.java deleted file mode 100644 index aaed9cbcb7c08..0000000000000 --- a/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/AssertHelper.java +++ /dev/null @@ -1,71 +0,0 @@ -package io.quarkus.virtual.rr; - -import java.lang.reflect.Method; - -import io.quarkus.arc.Arc; -import io.smallrye.common.vertx.VertxContext; -import io.vertx.core.Vertx; - -public class AssertHelper { - - /** - * Asserts that the current method: - * - runs on a duplicated context - * - runs on a virtual thread - * - has the request scope activated - */ - public static void assertEverything() { - assertThatTheRequestScopeIsActive(); - assertThatItRunsOnVirtualThread(); - assertThatItRunsOnADuplicatedContext(); - } - - public static void assertThatTheRequestScopeIsActive() { - if (!Arc.container().requestContext().isActive()) { - throw new AssertionError(("Expected the request scope to be active")); - } - } - - public static void assertThatItRunsOnADuplicatedContext() { - var context = Vertx.currentContext(); - if (context == null) { - throw new AssertionError("The method does not run on a Vert.x context"); - } - if (!VertxContext.isOnDuplicatedContext()) { - throw new AssertionError("The method does not run on a Vert.x **duplicated** context"); - } - } - - public static void assertThatItRunsOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (!virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is not a virtual thread"); - } - } catch (Exception e) { - throw new AssertionError( - "Thread " + Thread.currentThread() + " is not a virtual thread - cannot invoke Thread.isVirtual()", e); - } - } - - public static void assertNotOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is a virtual thread"); - } - } catch (Exception e) { - // Trying using Thread name. - var name = Thread.currentThread().toString(); - if (name.toLowerCase().contains("virtual")) { - throw new AssertionError("Thread " + Thread.currentThread() + " seems to be a virtual thread"); - } - } - } -} diff --git a/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/FilteredResource.java b/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/FilteredResource.java index ca3e2db5a18b6..e3794ae64eb42 100644 --- a/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/FilteredResource.java +++ b/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/FilteredResource.java @@ -7,6 +7,7 @@ import org.jboss.logmanager.MDC; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.smallrye.common.annotation.RunOnVirtualThread; import io.vertx.core.Vertx; @@ -19,7 +20,7 @@ public class FilteredResource { @GET @RunOnVirtualThread public Response filtered() { - AssertHelper.assertEverything(); + VirtualThreadsAssertions.assertEverything(); // Request scope assert counter.increment() == 2; diff --git a/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/Filters.java b/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/Filters.java index 214e886f58917..e3878252d4927 100644 --- a/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/Filters.java +++ b/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/Filters.java @@ -8,15 +8,14 @@ import org.jboss.resteasy.reactive.server.ServerRequestFilter; import org.jboss.resteasy.reactive.server.ServerResponseFilter; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.vertx.core.Vertx; public class Filters { @ServerRequestFilter(nonBlocking = true) public void request(ContainerRequestContext requestContext) { if (requestContext.getUriInfo().getPath().contains("/filter")) { - AssertHelper.assertNotOnVirtualThread(); - AssertHelper.assertThatItRunsOnADuplicatedContext(); - AssertHelper.assertThatTheRequestScopeIsActive(); + VirtualThreadsAssertions.assertWorkerOrEventLoopThread(); MDC.put("mdc", "test"); CDI.current().select(Counter.class).get().increment(); Vertx.currentContext().putLocal("filter", "test"); @@ -26,7 +25,7 @@ public void request(ContainerRequestContext requestContext) { @ServerResponseFilter public void getFilter(ContainerResponseContext responseContext) { if (responseContext.getHeaders().get("X-filter") != null) { - AssertHelper.assertEverything(); + VirtualThreadsAssertions.assertEverything(); // the request filter, the method, and here. assert CDI.current().select(Counter.class).get().increment() == 3; assert Vertx.currentContext().getLocal("test").equals("test test"); diff --git a/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/MyResource.java b/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/MyResource.java index 78699a422a2f7..35a79dc3330ed 100644 --- a/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/MyResource.java +++ b/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/MyResource.java @@ -4,6 +4,7 @@ import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.smallrye.common.annotation.NonBlocking; import io.smallrye.common.annotation.RunOnVirtualThread; import io.smallrye.mutiny.Multi; @@ -21,14 +22,14 @@ public class MyResource { @GET @RunOnVirtualThread public String testGet() { - AssertHelper.assertEverything(); + VirtualThreadsAssertions.assertEverything(); return "hello-" + counter.increment(); } @POST @RunOnVirtualThread public String testPost(String body) { - AssertHelper.assertEverything(); + VirtualThreadsAssertions.assertEverything(); return body + "-" + counter.increment(); } @@ -36,36 +37,30 @@ public String testPost(String body) { @NonBlocking @Path("/non-blocking") public String testNonBlocking() { - AssertHelper.assertThatTheRequestScopeIsActive(); - AssertHelper.assertThatItRunsOnADuplicatedContext(); - AssertHelper.assertNotOnVirtualThread(); + VirtualThreadsAssertions.assertWorkerOrEventLoopThread(); return "ok"; } @GET @Path("/uni") public Uni testUni() { - AssertHelper.assertThatTheRequestScopeIsActive(); - AssertHelper.assertThatItRunsOnADuplicatedContext(); - AssertHelper.assertNotOnVirtualThread(); + VirtualThreadsAssertions.assertWorkerOrEventLoopThread(); return Uni.createFrom().item("ok"); } @GET @Path("/multi") public Multi testMulti() { - AssertHelper.assertThatTheRequestScopeIsActive(); - AssertHelper.assertThatItRunsOnADuplicatedContext(); - AssertHelper.assertNotOnVirtualThread(); + VirtualThreadsAssertions.assertWorkerOrEventLoopThread(); return Multi.createFrom().items("o", "k"); } @GET @Path("/blocking") public String testBlocking() { - AssertHelper.assertThatTheRequestScopeIsActive(); - AssertHelper.assertThatItRunsOnADuplicatedContext(); - AssertHelper.assertNotOnVirtualThread(); + VirtualThreadsAssertions.assertThatTheRequestScopeIsActive(); + VirtualThreadsAssertions.assertThatItRunsOnADuplicatedContext(); + VirtualThreadsAssertions.assertNotOnVirtualThread(); return "hello-" + counter.increment(); } diff --git a/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/MyResourceWithVTOnClass.java b/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/MyResourceWithVTOnClass.java index f13718281a86b..0c860d4d1214b 100644 --- a/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/MyResourceWithVTOnClass.java +++ b/integration-tests/virtual-threads/resteasy-reactive-virtual-threads/src/main/java/io/quarkus/virtual/rr/MyResourceWithVTOnClass.java @@ -4,6 +4,7 @@ import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.smallrye.common.annotation.Blocking; import io.smallrye.common.annotation.RunOnVirtualThread; import io.smallrye.mutiny.Multi; @@ -21,13 +22,13 @@ public class MyResourceWithVTOnClass { @GET public String testGet() { - AssertHelper.assertEverything(); + VirtualThreadsAssertions.assertEverything(); return "hello-" + counter.increment(); } @POST public String testPost(String body) { - AssertHelper.assertEverything(); + VirtualThreadsAssertions.assertEverything(); return body + "-" + counter.increment(); } @@ -42,7 +43,7 @@ public Uni testUni() { @Path("/multi") @Blocking // Mandatory, because it's really a weird case public Multi testMulti() { - AssertHelper.assertEverything(); + VirtualThreadsAssertions.assertEverything(); return Multi.createFrom().items("o", "k"); } diff --git a/integration-tests/virtual-threads/scheduler-virtual-threads/pom.xml b/integration-tests/virtual-threads/scheduler-virtual-threads/pom.xml index 0d7b25e3c866a..6ab6114710b98 100644 --- a/integration-tests/virtual-threads/scheduler-virtual-threads/pom.xml +++ b/integration-tests/virtual-threads/scheduler-virtual-threads/pom.xml @@ -22,7 +22,11 @@ io.quarkus quarkus-scheduler - + + + io.quarkus + quarkus-test-vertx + io.quarkus quarkus-junit5 diff --git a/integration-tests/virtual-threads/scheduler-virtual-threads/src/main/java/io/quarkus/virtual/scheduler/AssertHelper.java b/integration-tests/virtual-threads/scheduler-virtual-threads/src/main/java/io/quarkus/virtual/scheduler/AssertHelper.java deleted file mode 100644 index c967414c5b3f8..0000000000000 --- a/integration-tests/virtual-threads/scheduler-virtual-threads/src/main/java/io/quarkus/virtual/scheduler/AssertHelper.java +++ /dev/null @@ -1,71 +0,0 @@ -package io.quarkus.virtual.scheduler; - -import java.lang.reflect.Method; - -import io.quarkus.arc.Arc; -import io.smallrye.common.vertx.VertxContext; -import io.vertx.core.Vertx; - -public class AssertHelper { - - /** - * Asserts that the current method: - * - runs on a duplicated context - * - runs on a virtual thread - * - has the request scope activated - */ - public static void assertEverything() { - assertThatTheRequestScopeIsActive(); - assertThatItRunsOnVirtualThread(); - assertThatItRunsOnADuplicatedContext(); - } - - public static void assertThatTheRequestScopeIsActive() { - if (!Arc.container().requestContext().isActive()) { - throw new AssertionError(("Expected the request scope to be active")); - } - } - - public static void assertThatItRunsOnADuplicatedContext() { - var context = Vertx.currentContext(); - if (context == null) { - throw new AssertionError("The method does not run on a Vert.x context"); - } - if (!VertxContext.isOnDuplicatedContext()) { - throw new AssertionError("The method does not run on a Vert.x **duplicated** context"); - } - } - - public static void assertThatItRunsOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (!virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is not a virtual thread"); - } - } catch (Exception e) { - throw new AssertionError( - "Thread " + Thread.currentThread() + " is not a virtual thread - cannot invoke Thread.isVirtual()", e); - } - } - - public static void assertNotOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is a virtual thread"); - } - } catch (Exception e) { - // Trying using Thread name. - var name = Thread.currentThread().toString(); - if (name.toLowerCase().contains("virtual")) { - throw new AssertionError("Thread " + Thread.currentThread() + " seems to be a virtual thread"); - } - } - } -} diff --git a/integration-tests/virtual-threads/scheduler-virtual-threads/src/main/java/io/quarkus/virtual/scheduler/ScheduledResource.java b/integration-tests/virtual-threads/scheduler-virtual-threads/src/main/java/io/quarkus/virtual/scheduler/ScheduledResource.java index 0b4588c16dbfb..143fcf34c1a09 100644 --- a/integration-tests/virtual-threads/scheduler-virtual-threads/src/main/java/io/quarkus/virtual/scheduler/ScheduledResource.java +++ b/integration-tests/virtual-threads/scheduler-virtual-threads/src/main/java/io/quarkus/virtual/scheduler/ScheduledResource.java @@ -10,6 +10,7 @@ import io.quarkus.runtime.StartupEvent; import io.quarkus.scheduler.Scheduled; import io.quarkus.scheduler.Scheduler; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.smallrye.common.annotation.RunOnVirtualThread; @Path("/") @@ -22,7 +23,7 @@ public void init(@Observes StartupEvent ev, Scheduler scheduler) { scheduler.newJob("my-programmatic-job") .setInterval("1s") .setTask(ex -> { - AssertHelper.assertEverything(); + VirtualThreadsAssertions.assertEverything(); // Quarkus specific - each VT has a unique name programmaticExecutions.add(Thread.currentThread().getName()); }, true) @@ -32,7 +33,7 @@ public void init(@Observes StartupEvent ev, Scheduler scheduler) { @Scheduled(every = "1s") @RunOnVirtualThread void run() { - AssertHelper.assertEverything(); + VirtualThreadsAssertions.assertEverything(); // Quarkus specific - each VT has a unique name executions.add(Thread.currentThread().getName()); } diff --git a/integration-tests/virtual-threads/vertx-event-bus-virtual-threads/pom.xml b/integration-tests/virtual-threads/vertx-event-bus-virtual-threads/pom.xml index 57617bea7d8fb..98100a257bf91 100644 --- a/integration-tests/virtual-threads/vertx-event-bus-virtual-threads/pom.xml +++ b/integration-tests/virtual-threads/vertx-event-bus-virtual-threads/pom.xml @@ -18,7 +18,11 @@ io.quarkus quarkus-resteasy-reactive-jackson - + + + io.quarkus + quarkus-test-vertx + io.quarkus quarkus-junit5 diff --git a/integration-tests/virtual-threads/vertx-event-bus-virtual-threads/src/main/java/io/quarkus/virtual/vertx/AssertHelper.java b/integration-tests/virtual-threads/vertx-event-bus-virtual-threads/src/main/java/io/quarkus/virtual/vertx/AssertHelper.java deleted file mode 100644 index ff75aa955dfa5..0000000000000 --- a/integration-tests/virtual-threads/vertx-event-bus-virtual-threads/src/main/java/io/quarkus/virtual/vertx/AssertHelper.java +++ /dev/null @@ -1,71 +0,0 @@ -package io.quarkus.virtual.vertx; - -import java.lang.reflect.Method; - -import io.quarkus.arc.Arc; -import io.smallrye.common.vertx.VertxContext; -import io.vertx.core.Vertx; - -public class AssertHelper { - - /** - * Asserts that the current method: - * - runs on a duplicated context - * - runs on a virtual thread - * - has the request scope activated - */ - public static void assertEverything() { - assertThatTheRequestScopeIsActive(); - assertThatItRunsOnVirtualThread(); - assertThatItRunsOnADuplicatedContext(); - } - - public static void assertThatTheRequestScopeIsActive() { - if (!Arc.container().requestContext().isActive()) { - throw new AssertionError(("Expected the request scope to be active")); - } - } - - public static void assertThatItRunsOnADuplicatedContext() { - var context = Vertx.currentContext(); - if (context == null) { - throw new AssertionError("The method does not run on a Vert.x context"); - } - if (!VertxContext.isOnDuplicatedContext()) { - throw new AssertionError("The method does not run on a Vert.x **duplicated** context"); - } - } - - public static void assertThatItRunsOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (!virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is not a virtual thread"); - } - } catch (Exception e) { - throw new AssertionError( - "Thread " + Thread.currentThread() + " is not a virtual thread - cannot invoke Thread.isVirtual()", e); - } - } - - public static void assertNotOnVirtualThread() { - // We cannot depend on a Java 20. - try { - Method isVirtual = Thread.class.getMethod("isVirtual"); - isVirtual.setAccessible(true); - boolean virtual = (Boolean) isVirtual.invoke(Thread.currentThread()); - if (virtual) { - throw new AssertionError("Thread " + Thread.currentThread() + " is a virtual thread"); - } - } catch (Exception e) { - // Trying using Thread name. - var name = Thread.currentThread().toString(); - if (name.toLowerCase().contains("virtual")) { - throw new AssertionError("Thread " + Thread.currentThread() + " seems to be a virtual thread"); - } - } - } -} diff --git a/integration-tests/virtual-threads/vertx-event-bus-virtual-threads/src/main/java/io/quarkus/virtual/vertx/EventBusConsumer.java b/integration-tests/virtual-threads/vertx-event-bus-virtual-threads/src/main/java/io/quarkus/virtual/vertx/EventBusConsumer.java index 04dec854bc8b9..1cfadaedaa311 100644 --- a/integration-tests/virtual-threads/vertx-event-bus-virtual-threads/src/main/java/io/quarkus/virtual/vertx/EventBusConsumer.java +++ b/integration-tests/virtual-threads/vertx-event-bus-virtual-threads/src/main/java/io/quarkus/virtual/vertx/EventBusConsumer.java @@ -5,6 +5,7 @@ import jakarta.enterprise.context.ApplicationScoped; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.quarkus.vertx.ConsumeEvent; import io.smallrye.common.annotation.RunOnVirtualThread; @@ -16,14 +17,14 @@ public class EventBusConsumer { @ConsumeEvent("one-way") @RunOnVirtualThread void receive(String m) { - AssertHelper.assertEverything(); + VirtualThreadsAssertions.assertEverything(); ONE_WAY.add(m); } @ConsumeEvent("request-reply") @RunOnVirtualThread String process(String m) { - AssertHelper.assertEverything(); + VirtualThreadsAssertions.assertEverything(); return m.toUpperCase(); } diff --git a/integration-tests/virtual-threads/virtual-threads-disabled/pom.xml b/integration-tests/virtual-threads/virtual-threads-disabled/pom.xml index cf83eb35efc5d..bb248223015e0 100644 --- a/integration-tests/virtual-threads/virtual-threads-disabled/pom.xml +++ b/integration-tests/virtual-threads/virtual-threads-disabled/pom.xml @@ -18,7 +18,11 @@ io.quarkus quarkus-resteasy-reactive-jackson - + + + io.quarkus + quarkus-test-vertx + io.quarkus quarkus-junit5 diff --git a/integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/FilteredResource.java b/integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/FilteredResource.java index e1dba7b7d0a27..926c8efbc4ed4 100644 --- a/integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/FilteredResource.java +++ b/integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/FilteredResource.java @@ -7,6 +7,7 @@ import org.jboss.logmanager.MDC; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.smallrye.common.annotation.RunOnVirtualThread; import io.vertx.core.Vertx; @@ -19,7 +20,7 @@ public class FilteredResource { @GET @RunOnVirtualThread public Response filtered() { - AssertHelper.assertWorkerOrEventLoopThread(); + VirtualThreadsAssertions.assertWorkerOrEventLoopThread(); // Request scope assert counter.increment() == 2; diff --git a/integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/Filters.java b/integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/Filters.java index 6ab40068d675f..1437b344be258 100644 --- a/integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/Filters.java +++ b/integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/Filters.java @@ -8,15 +8,14 @@ import org.jboss.resteasy.reactive.server.ServerRequestFilter; import org.jboss.resteasy.reactive.server.ServerResponseFilter; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.vertx.core.Vertx; public class Filters { @ServerRequestFilter(nonBlocking = true) public void request(ContainerRequestContext requestContext) { if (requestContext.getUriInfo().getPath().contains("/filter")) { - AssertHelper.assertNotOnVirtualThread(); - AssertHelper.assertThatItRunsOnADuplicatedContext(); - AssertHelper.assertThatTheRequestScopeIsActive(); + VirtualThreadsAssertions.assertWorkerOrEventLoopThread(); MDC.put("mdc", "test"); CDI.current().select(Counter.class).get().increment(); Vertx.currentContext().putLocal("filter", "test"); @@ -26,7 +25,7 @@ public void request(ContainerRequestContext requestContext) { @ServerResponseFilter public void getFilter(ContainerResponseContext responseContext) { if (responseContext.getHeaders().get("X-filter") != null) { - AssertHelper.assertWorkerOrEventLoopThread(); + VirtualThreadsAssertions.assertWorkerOrEventLoopThread(); // the request filter, the method, and here. assert CDI.current().select(Counter.class).get().increment() == 3; assert Vertx.currentContext().getLocal("test").equals("test test"); diff --git a/integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/MyResource.java b/integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/MyResource.java index a8d5fd5283856..61b08f7acfb3e 100644 --- a/integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/MyResource.java +++ b/integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/MyResource.java @@ -4,6 +4,7 @@ import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.smallrye.common.annotation.NonBlocking; import io.smallrye.common.annotation.RunOnVirtualThread; import io.smallrye.mutiny.Multi; @@ -21,14 +22,14 @@ public class MyResource { @GET @RunOnVirtualThread public String testGet() { - AssertHelper.assertWorkerOrEventLoopThread(); + VirtualThreadsAssertions.assertWorkerOrEventLoopThread(); return "hello-" + counter.increment(); } @POST @RunOnVirtualThread public String testPost(String body) { - AssertHelper.assertWorkerOrEventLoopThread(); + VirtualThreadsAssertions.assertWorkerOrEventLoopThread(); return body + "-" + counter.increment(); } @@ -36,34 +37,28 @@ public String testPost(String body) { @NonBlocking @Path("/non-blocking") public String testNonBlocking() { - AssertHelper.assertWorkerOrEventLoopThread(); + VirtualThreadsAssertions.assertWorkerOrEventLoopThread(); return "ok"; } @GET @Path("/uni") public Uni testUni() { - AssertHelper.assertThatTheRequestScopeIsActive(); - AssertHelper.assertThatItRunsOnADuplicatedContext(); - AssertHelper.assertNotOnVirtualThread(); + VirtualThreadsAssertions.assertWorkerOrEventLoopThread(); return Uni.createFrom().item("ok"); } @GET @Path("/multi") public Multi testMulti() { - AssertHelper.assertThatTheRequestScopeIsActive(); - AssertHelper.assertThatItRunsOnADuplicatedContext(); - AssertHelper.assertNotOnVirtualThread(); + VirtualThreadsAssertions.assertWorkerOrEventLoopThread(); return Multi.createFrom().items("o", "k"); } @GET @Path("/blocking") public String testBlocking() { - AssertHelper.assertThatTheRequestScopeIsActive(); - AssertHelper.assertThatItRunsOnADuplicatedContext(); - AssertHelper.assertNotOnVirtualThread(); + VirtualThreadsAssertions.assertWorkerOrEventLoopThread(); return "hello-" + counter.increment(); } diff --git a/integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/MyResourceWithVTOnClass.java b/integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/MyResourceWithVTOnClass.java index f6969e8dcfe68..b590b35fcd1b9 100644 --- a/integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/MyResourceWithVTOnClass.java +++ b/integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/MyResourceWithVTOnClass.java @@ -4,6 +4,7 @@ import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; +import io.quarkus.test.vertx.VirtualThreadsAssertions; import io.smallrye.common.annotation.Blocking; import io.smallrye.common.annotation.RunOnVirtualThread; import io.smallrye.mutiny.Multi; @@ -21,13 +22,13 @@ public class MyResourceWithVTOnClass { @GET public String testGet() { - AssertHelper.assertWorkerOrEventLoopThread(); + VirtualThreadsAssertions.assertWorkerOrEventLoopThread(); return "hello-" + counter.increment(); } @POST public String testPost(String body) { - AssertHelper.assertWorkerOrEventLoopThread(); + VirtualThreadsAssertions.assertWorkerOrEventLoopThread(); return body + "-" + counter.increment(); } @@ -42,7 +43,7 @@ public Uni testUni() { @Path("/multi") @Blocking // Mandatory, because it's really a weird case public Multi testMulti() { - AssertHelper.assertWorkerOrEventLoopThread(); + VirtualThreadsAssertions.assertWorkerOrEventLoopThread(); return Multi.createFrom().items("o", "k"); } diff --git a/integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/AssertHelper.java b/test-framework/vertx/src/main/java/io/quarkus/test/vertx/VirtualThreadsAssertions.java similarity index 97% rename from integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/AssertHelper.java rename to test-framework/vertx/src/main/java/io/quarkus/test/vertx/VirtualThreadsAssertions.java index 2376bc122bd2a..53589a420b9cd 100644 --- a/integration-tests/virtual-threads/virtual-threads-disabled/src/main/java/io/quarkus/virtual/disabled/AssertHelper.java +++ b/test-framework/vertx/src/main/java/io/quarkus/test/vertx/VirtualThreadsAssertions.java @@ -1,4 +1,4 @@ -package io.quarkus.virtual.disabled; +package io.quarkus.test.vertx; import java.lang.reflect.Method; @@ -6,7 +6,7 @@ import io.smallrye.common.vertx.VertxContext; import io.vertx.core.Vertx; -public class AssertHelper { +public class VirtualThreadsAssertions { /** * Asserts that the current method: