diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestTracingProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestTracingProcessor.java index 7e2777caaa5e41..89daef853919dc 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestTracingProcessor.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestTracingProcessor.java @@ -25,6 +25,7 @@ import io.quarkus.deployment.builditem.ServiceStartBuildItem; import io.quarkus.deployment.logging.LogCleanupFilterBuildItem; import io.quarkus.dev.spi.DevModeType; +import io.quarkus.dev.testing.ContinuousTestingSharedStateManager; import io.quarkus.dev.testing.TracingHandler; import io.quarkus.gizmo.Gizmo; @@ -82,6 +83,8 @@ void startTesting(TestConfig config, LiveReloadBuildItem liveReloadBuildItem, testSupport.stop(); } } + QuarkusClassLoader cl = (QuarkusClassLoader) Thread.currentThread().getContextClassLoader(); + ((QuarkusClassLoader) cl.parent()).addCloseTask(ContinuousTestingSharedStateManager::reset); } @BuildStep(onlyIf = IsTest.class) diff --git a/extensions/amazon-lambda/common-deployment/src/main/java/io/quarkus/amazon/lambda/deployment/DevServicesLambdaProcessor.java b/extensions/amazon-lambda/common-deployment/src/main/java/io/quarkus/amazon/lambda/deployment/DevServicesLambdaProcessor.java index 6b41e5100b0c96..e1fbd0fdb33cff 100644 --- a/extensions/amazon-lambda/common-deployment/src/main/java/io/quarkus/amazon/lambda/deployment/DevServicesLambdaProcessor.java +++ b/extensions/amazon-lambda/common-deployment/src/main/java/io/quarkus/amazon/lambda/deployment/DevServicesLambdaProcessor.java @@ -15,7 +15,7 @@ import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.annotations.Record; -import io.quarkus.deployment.builditem.DevServicesNativeConfigResultBuildItem; +import io.quarkus.deployment.builditem.DevServicesConfigResultBuildItem; import io.quarkus.deployment.builditem.LaunchModeBuildItem; import io.quarkus.deployment.builditem.ServiceStartBuildItem; import io.quarkus.runtime.LaunchMode; @@ -51,7 +51,7 @@ private boolean legacyTestingEnabled() { public void startEventServer(LaunchModeBuildItem launchMode, LambdaConfig config, Optional override, - BuildProducer devServicePropertiesProducer, + BuildProducer devServicePropertiesProducer, BuildProducer serviceStartBuildItemBuildProducer) throws Exception { if (!launchMode.getLaunchMode().isDevOrTest()) return; @@ -73,9 +73,8 @@ public void startEventServer(LaunchModeBuildItem launchMode, startMode = launchMode.getLaunchMode(); server.start(port); String baseUrl = "localhost:" + port + MockEventServer.BASE_PATH; - System.setProperty(AmazonLambdaApi.QUARKUS_INTERNAL_AWS_LAMBDA_TEST_API, baseUrl); devServicePropertiesProducer.produce( - new DevServicesNativeConfigResultBuildItem(AmazonLambdaApi.QUARKUS_INTERNAL_AWS_LAMBDA_TEST_API, baseUrl)); + new DevServicesConfigResultBuildItem(AmazonLambdaApi.QUARKUS_INTERNAL_AWS_LAMBDA_TEST_API, baseUrl)); Runnable closeTask = () -> { if (server != null) { try { diff --git a/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AbstractLambdaPollLoop.java b/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AbstractLambdaPollLoop.java index 1d7052ccc766df..eb861016d78eae 100644 --- a/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AbstractLambdaPollLoop.java +++ b/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AbstractLambdaPollLoop.java @@ -16,19 +16,23 @@ import com.fasterxml.jackson.databind.ObjectReader; import io.quarkus.runtime.Application; +import io.quarkus.runtime.LaunchMode; import io.quarkus.runtime.ShutdownContext; public abstract class AbstractLambdaPollLoop { private static final Logger log = Logger.getLogger(AbstractLambdaPollLoop.class); - private ObjectMapper objectMapper; - private ObjectReader cognitoIdReader; - private ObjectReader clientCtxReader; + private final ObjectMapper objectMapper; + private final ObjectReader cognitoIdReader; + private final ObjectReader clientCtxReader; + private final LaunchMode launchMode; - public AbstractLambdaPollLoop(ObjectMapper objectMapper, ObjectReader cognitoIdReader, ObjectReader clientCtxReader) { + public AbstractLambdaPollLoop(ObjectMapper objectMapper, ObjectReader cognitoIdReader, ObjectReader clientCtxReader, + LaunchMode launchMode) { this.objectMapper = objectMapper; this.cognitoIdReader = cognitoIdReader; this.clientCtxReader = clientCtxReader; + this.launchMode = launchMode; } protected abstract boolean isStream(); @@ -45,7 +49,7 @@ public void startPollLoop(ShutdownContext context) { @Override public void run() { try { - if (!LambdaHotReplacementRecorder.enabled) { + if (!LambdaHotReplacementRecorder.enabled && launchMode == LaunchMode.DEVELOPMENT) { // when running with continuous testing, this method fails // because currentApplication is not set when running as an // auxiliary application. So, just skip it if hot replacement enabled. @@ -81,7 +85,7 @@ public void run() { continue; } try { - if (LambdaHotReplacementRecorder.enabled) { + if (LambdaHotReplacementRecorder.enabled && launchMode == LaunchMode.DEVELOPMENT) { try { // do not interrupt during a hot replacement // as shutdown will abort and do nasty things. @@ -125,7 +129,7 @@ public void run() { if (abortGracefully(e)) { return; } - log.error("Failed to run lambda", e); + log.error("Failed to run lambda (" + launchMode + ")", e); postError(AmazonLambdaApi.invocationError(baseUrl, requestId), new FunctionError(e.getClass().getName(), e.getMessage())); @@ -134,7 +138,7 @@ public void run() { } catch (Exception e) { if (!abortGracefully(e)) - log.error("Error running lambda", e); + log.error("Error running lambda (" + launchMode + ")", e); Application app = Application.currentApplication(); if (app != null) { app.stop(); @@ -150,24 +154,24 @@ public void run() { } } catch (Exception e) { try { - log.error("Lambda init error", e); + log.error("Lambda init error (" + launchMode + ")", e); postError(AmazonLambdaApi.initError(baseUrl), new FunctionError(e.getClass().getName(), e.getMessage())); } catch (Exception ex) { - log.error("Failed to report init error", ex); + log.error("Failed to report init error (" + launchMode + ")", ex); } finally { // our main loop is done, time to shutdown Application app = Application.currentApplication(); if (app != null) { - log.error("Shutting down Quarkus application because of error"); + log.error("Shutting down Quarkus application because of error (" + launchMode + ")"); app.stop(); } } } finally { - log.info("Lambda polling thread complete"); + log.info("Lambda polling thread complete (" + launchMode + ")"); } } - }, "Lambda Thread"); + }, "Lambda Thread (" + launchMode + ")"); pollingThread.setDaemon(true); context.addShutdownTask(() -> { running.set(false); @@ -261,7 +265,7 @@ boolean abortGracefully(Exception ex) { // if we are running in test mode, or native mode outside of the lambda container, then don't output stack trace for socket errors boolean lambdaEnv = System.getenv("AWS_LAMBDA_RUNTIME_API") != null; - boolean testEnv = System.getProperty(AmazonLambdaApi.QUARKUS_INTERNAL_AWS_LAMBDA_TEST_API) != null; + boolean testEnv = LaunchMode.current() == LaunchMode.TEST; boolean graceful = ((ex instanceof SocketException || ex instanceof ConnectException) && testEnv) || (ex instanceof UnknownHostException && !lambdaEnv); diff --git a/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaApi.java b/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaApi.java index ec1e528ab38753..5b04cbf30bde53 100644 --- a/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaApi.java +++ b/extensions/amazon-lambda/common-runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaApi.java @@ -3,6 +3,10 @@ import java.net.MalformedURLException; import java.net.URL; +import org.eclipse.microprofile.config.ConfigProvider; + +import io.quarkus.runtime.LaunchMode; + /** * Various constants and util methods used for communication with the AWS API. */ @@ -80,13 +84,15 @@ static String functionVersion() { } public static boolean isTestMode() { - return System.getProperty(AmazonLambdaApi.QUARKUS_INTERNAL_AWS_LAMBDA_TEST_API) != null; + //need this config check for native tests + return LaunchMode.current() == LaunchMode.TEST + || ConfigProvider.getConfig().getOptionalValue(QUARKUS_INTERNAL_AWS_LAMBDA_TEST_API, String.class).isPresent(); } private static String runtimeApi() { - String testApi = System.getProperty(QUARKUS_INTERNAL_AWS_LAMBDA_TEST_API); - if (testApi != null) { - return testApi; + var testApi = ConfigProvider.getConfig().getOptionalValue(QUARKUS_INTERNAL_AWS_LAMBDA_TEST_API, String.class); + if (testApi.isPresent()) { + return testApi.get(); } return System.getenv("AWS_LAMBDA_RUNTIME_API"); } diff --git a/extensions/amazon-lambda/deployment/src/main/java/io/quarkus/amazon/lambda/deployment/AmazonLambdaProcessor.java b/extensions/amazon-lambda/deployment/src/main/java/io/quarkus/amazon/lambda/deployment/AmazonLambdaProcessor.java index b755f0aae7f7b2..7b14804bf98346 100644 --- a/extensions/amazon-lambda/deployment/src/main/java/io/quarkus/amazon/lambda/deployment/AmazonLambdaProcessor.java +++ b/extensions/amazon-lambda/deployment/src/main/java/io/quarkus/amazon/lambda/deployment/AmazonLambdaProcessor.java @@ -240,9 +240,10 @@ public void recordHandlerClass(List lambdas, @Record(value = ExecutionTime.RUNTIME_INIT) void startPoolLoop(AmazonLambdaRecorder recorder, ShutdownContextBuildItem shutdownContextBuildItem, + LaunchModeBuildItem launchModeBuildItem, List orderServicesFirst // try to order this after service recorders ) { - recorder.startPollLoop(shutdownContextBuildItem); + recorder.startPollLoop(shutdownContextBuildItem, launchModeBuildItem.getLaunchMode()); } @BuildStep @@ -253,7 +254,7 @@ void startPoolLoopDevOrTest(AmazonLambdaRecorder recorder, LaunchModeBuildItem launchModeBuildItem) { LaunchMode mode = launchModeBuildItem.getLaunchMode(); if (mode.isDevOrTest()) { - recorder.startPollLoop(shutdownContextBuildItem); + recorder.startPollLoop(shutdownContextBuildItem, mode); } } diff --git a/extensions/amazon-lambda/deployment/src/test/java/io/quarkus/amazon/lambda/deployment/testing/LambdaDevServicesContinuousTestingTestCase.java b/extensions/amazon-lambda/deployment/src/test/java/io/quarkus/amazon/lambda/deployment/testing/LambdaDevServicesContinuousTestingTestCase.java index 1565016006b699..c0007951bd289f 100644 --- a/extensions/amazon-lambda/deployment/src/test/java/io/quarkus/amazon/lambda/deployment/testing/LambdaDevServicesContinuousTestingTestCase.java +++ b/extensions/amazon-lambda/deployment/src/test/java/io/quarkus/amazon/lambda/deployment/testing/LambdaDevServicesContinuousTestingTestCase.java @@ -6,7 +6,7 @@ import org.jboss.shrinkwrap.api.asset.StringAsset; import org.jboss.shrinkwrap.api.spec.JavaArchive; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.RepeatedTest; import org.junit.jupiter.api.extension.RegisterExtension; import io.quarkus.test.ContinuousTestingTestUtils; @@ -30,7 +30,8 @@ public JavaArchive get() { } }); - @Test + //run this twice, to make sure everything is cleaned up properly + @RepeatedTest(2) public void testLambda() throws Exception { ContinuousTestingTestUtils utils = new ContinuousTestingTestUtils(); var result = utils.waitForNextCompletion(); diff --git a/extensions/amazon-lambda/event-server/src/main/java/io/quarkus/amazon/lambda/runtime/MockEventServer.java b/extensions/amazon-lambda/event-server/src/main/java/io/quarkus/amazon/lambda/runtime/MockEventServer.java index cea6dfd37e2315..8c123ace9abaa6 100644 --- a/extensions/amazon-lambda/event-server/src/main/java/io/quarkus/amazon/lambda/runtime/MockEventServer.java +++ b/extensions/amazon-lambda/event-server/src/main/java/io/quarkus/amazon/lambda/runtime/MockEventServer.java @@ -5,6 +5,7 @@ import java.util.UUID; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; @@ -24,21 +25,6 @@ public class MockEventServer implements Closeable { protected static final Logger log = Logger.getLogger(MockEventServer.class); public static final int DEFAULT_PORT = 8081; - public void start() { - int port = DEFAULT_PORT; - start(port); - } - - public void start(int port) { - this.port = port; - vertx = Vertx.vertx(); - httpServer = vertx.createHttpServer(); - router = Router.router(vertx); - setupRoutes(); - httpServer.requestHandler(router).listen(port).result(); - log.info("Mock Lambda Event Server Started"); - } - private Vertx vertx; private int port; protected HttpServer httpServer; @@ -55,6 +41,25 @@ public MockEventServer() { queue = new LinkedBlockingQueue<>(); } + public void start() { + int port = DEFAULT_PORT; + start(port); + } + + public void start(int port) { + this.port = port; + vertx = Vertx.vertx(); + httpServer = vertx.createHttpServer(); + router = Router.router(vertx); + setupRoutes(); + try { + httpServer.requestHandler(router).listen(port).toCompletionStage().toCompletableFuture().get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + log.info("Mock Lambda Event Server Started"); + } + public HttpServer getHttpServer() { return httpServer; } @@ -233,8 +238,18 @@ public void processError(RoutingContext ctx, RoutingContext pending, Buffer buff @Override public void close() throws IOException { log.info("Stopping Mock Lambda Event Server"); - httpServer.close().result(); - vertx.close().result(); - blockingPool.shutdown(); + try { + httpServer.close().toCompletionStage().toCompletableFuture().get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } finally { + try { + vertx.close().toCompletionStage().toCompletableFuture().get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } finally { + blockingPool.shutdown(); + } + } } } diff --git a/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java b/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java index 025873490e4334..6fdc74a0b6bab8 100644 --- a/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java +++ b/extensions/amazon-lambda/runtime/src/main/java/io/quarkus/amazon/lambda/runtime/AmazonLambdaRecorder.java @@ -17,6 +17,7 @@ import io.quarkus.amazon.lambda.runtime.handlers.S3EventInputReader; import io.quarkus.arc.runtime.BeanContainer; +import io.quarkus.runtime.LaunchMode; import io.quarkus.runtime.ShutdownContext; import io.quarkus.runtime.annotations.Recorder; @@ -145,9 +146,9 @@ public void chooseHandlerClass(List>> uname } @SuppressWarnings("rawtypes") - public void startPollLoop(ShutdownContext context) { + public void startPollLoop(ShutdownContext context, LaunchMode launchMode) { AbstractLambdaPollLoop loop = new AbstractLambdaPollLoop(AmazonLambdaMapperRecorder.objectMapper, - AmazonLambdaMapperRecorder.cognitoIdReader, AmazonLambdaMapperRecorder.clientCtxReader) { + AmazonLambdaMapperRecorder.cognitoIdReader, AmazonLambdaMapperRecorder.clientCtxReader, launchMode) { @Override protected Object processRequest(Object input, AmazonLambdaContext context) throws Exception { diff --git a/extensions/funqy/funqy-amazon-lambda/deployment/src/main/java/io/quarkus/funqy/deployment/bindings/FunqyLambdaBuildStep.java b/extensions/funqy/funqy-amazon-lambda/deployment/src/main/java/io/quarkus/funqy/deployment/bindings/FunqyLambdaBuildStep.java index 82887800d171c2..6a8bcbdc213d9c 100644 --- a/extensions/funqy/funqy-amazon-lambda/deployment/src/main/java/io/quarkus/funqy/deployment/bindings/FunqyLambdaBuildStep.java +++ b/extensions/funqy/funqy-amazon-lambda/deployment/src/main/java/io/quarkus/funqy/deployment/bindings/FunqyLambdaBuildStep.java @@ -59,9 +59,10 @@ public RuntimeComplete choose(FunqyConfig config, FunqyLambdaBindingRecorder rec public void startPoolLoop(FunqyLambdaBindingRecorder recorder, RuntimeComplete ignored, ShutdownContextBuildItem shutdownContextBuildItem, + LaunchModeBuildItem launchModeBuildItem, List orderServicesFirst // try to order this after service recorders ) { - recorder.startPollLoop(shutdownContextBuildItem); + recorder.startPollLoop(shutdownContextBuildItem, launchModeBuildItem.getLaunchMode()); } @BuildStep @@ -73,7 +74,7 @@ public void startPoolLoopDevOrTest(RuntimeComplete ignored, LaunchModeBuildItem launchModeBuildItem) { LaunchMode mode = launchModeBuildItem.getLaunchMode(); if (mode.isDevOrTest()) { - recorder.startPollLoop(shutdownContextBuildItem); + recorder.startPollLoop(shutdownContextBuildItem, mode); } } } diff --git a/extensions/funqy/funqy-amazon-lambda/runtime/src/main/java/io/quarkus/funqy/lambda/FunqyLambdaBindingRecorder.java b/extensions/funqy/funqy-amazon-lambda/runtime/src/main/java/io/quarkus/funqy/lambda/FunqyLambdaBindingRecorder.java index 03ac85133e80cd..d2726940abd858 100644 --- a/extensions/funqy/funqy-amazon-lambda/runtime/src/main/java/io/quarkus/funqy/lambda/FunqyLambdaBindingRecorder.java +++ b/extensions/funqy/funqy-amazon-lambda/runtime/src/main/java/io/quarkus/funqy/lambda/FunqyLambdaBindingRecorder.java @@ -27,6 +27,7 @@ import io.quarkus.funqy.runtime.FunqyConfig; import io.quarkus.funqy.runtime.FunqyServerResponse; import io.quarkus.funqy.runtime.RequestContextImpl; +import io.quarkus.runtime.LaunchMode; import io.quarkus.runtime.ShutdownContext; import io.quarkus.runtime.annotations.Recorder; @@ -107,9 +108,9 @@ public static void handle(InputStream inputStream, OutputStream outputStream, Co } @SuppressWarnings("rawtypes") - public void startPollLoop(ShutdownContext context) { + public void startPollLoop(ShutdownContext context, LaunchMode launchMode) { AbstractLambdaPollLoop loop = new AbstractLambdaPollLoop(AmazonLambdaMapperRecorder.objectMapper, - AmazonLambdaMapperRecorder.cognitoIdReader, AmazonLambdaMapperRecorder.clientCtxReader) { + AmazonLambdaMapperRecorder.cognitoIdReader, AmazonLambdaMapperRecorder.clientCtxReader, launchMode) { @Override protected Object processRequest(Object input, AmazonLambdaContext context) throws Exception { diff --git a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/tests/TestsProcessor.java b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/tests/TestsProcessor.java index 8b58de97ce3ff5..04d51e13b7acad 100644 --- a/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/tests/TestsProcessor.java +++ b/extensions/vertx-http/deployment/src/main/java/io/quarkus/vertx/http/deployment/devmode/tests/TestsProcessor.java @@ -58,7 +58,7 @@ public void setupTestRoutes( // Add continuous testing routeBuildItemBuildProducer.produce(nonApplicationRootPathBuildItem.routeBuilder() .route("dev/test") - .handler(recorder.continousTestHandler(shutdownContextBuildItem)) + .handler(recorder.continuousTestHandler(shutdownContextBuildItem)) .build()); } diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/devmode/DevConsoleRecorder.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/devmode/DevConsoleRecorder.java index 8b2e5cb4ee7558..57b06b28fc00d2 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/devmode/DevConsoleRecorder.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/devmode/DevConsoleRecorder.java @@ -45,7 +45,7 @@ public Handler devConsoleHandler(String devConsoleFinalDestinati return new DevConsoleStaticHandler(devConsoleFinalDestination); } - public Handler continousTestHandler(ShutdownContext context) { + public Handler continuousTestHandler(ShutdownContext context) { ContinuousTestWebSocketHandler handler = new ContinuousTestWebSocketHandler(); ContinuousTestingSharedStateManager.addStateListener(handler);