From e64c2533993f5a95d779e9bde58ff19d53b574dd Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 6 Jun 2023 10:09:06 +0300 Subject: [PATCH 1/3] Add support for passing environment variables in `@QuarkusIntegrationTest` Relates to: #33806 --- .../deployment/dev/testing/TestConfig.java | 6 ++++ .../test-extension/tests/pom.xml | 3 ++ .../io/quarkus/it/extension/DummyMapping.java | 16 ++++++++++ .../EnvironmentVariableTestEndpoint.java | 20 +++++++++++++ .../src/main/resources/application.properties | 2 ++ .../it/extension/EnvVarGraalITCase.java | 18 +++++++++++ .../quarkus/it/extension/EnvVarTestCase.java | 18 +++++++++++ .../quarkus/test/common/ArtifactLauncher.java | 7 +++++ .../DefaultDockerContainerLauncher.java | 14 +++++++-- .../test/common/DefaultJarLauncher.java | 6 ++-- .../common/DefaultNativeImageLauncher.java | 6 ++-- .../io/quarkus/test/common/LauncherUtil.java | 30 +++++++++++++++++-- .../test/junit/NativeTestExtension.java | 1 + .../test/junit/launcher/ConfigUtil.java | 8 +++++ .../launcher/DefaultInitContextBase.java | 12 +++++++- .../DockerContainerLauncherProvider.java | 6 ++-- .../junit/launcher/JarLauncherProvider.java | 7 +++-- .../launcher/NativeImageLauncherProvider.java | 7 +++-- 18 files changed, 171 insertions(+), 16 deletions(-) create mode 100644 integration-tests/test-extension/tests/src/main/java/io/quarkus/it/extension/DummyMapping.java create mode 100644 integration-tests/test-extension/tests/src/main/java/io/quarkus/it/extension/EnvironmentVariableTestEndpoint.java create mode 100644 integration-tests/test-extension/tests/src/test/java/io/quarkus/it/extension/EnvVarGraalITCase.java create mode 100644 integration-tests/test-extension/tests/src/test/java/io/quarkus/it/extension/EnvVarTestCase.java diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java index 1874eeaaf894f..726232607ce04 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java @@ -182,6 +182,12 @@ public class TestConfig { @ConfigItem(defaultValue = "") Optional> argLine; + /** + * Additional environment variables to be set in the process that {@code @QuarkusIntegrationTest} launches. + */ + @ConfigItem + Map env; + /** * Used in {@code @QuarkusIntegrationTest} to determine how long the test will wait for the * application to launch diff --git a/integration-tests/test-extension/tests/pom.xml b/integration-tests/test-extension/tests/pom.xml index 006dc4c8e25be..97c5f61be0934 100644 --- a/integration-tests/test-extension/tests/pom.xml +++ b/integration-tests/test-extension/tests/pom.xml @@ -140,6 +140,9 @@ ${project.build.directory}/recorded-classpath-entries-failsafe.txt test + + 70 + diff --git a/integration-tests/test-extension/tests/src/main/java/io/quarkus/it/extension/DummyMapping.java b/integration-tests/test-extension/tests/src/main/java/io/quarkus/it/extension/DummyMapping.java new file mode 100644 index 0000000000000..3653c2156ba97 --- /dev/null +++ b/integration-tests/test-extension/tests/src/main/java/io/quarkus/it/extension/DummyMapping.java @@ -0,0 +1,16 @@ +package io.quarkus.it.extension; + +import io.quarkus.arc.Unremovable; +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithDefault; + +@ConfigMapping(prefix = "dummy") +@Unremovable +public interface DummyMapping { + + @WithDefault("foo") + String name(); + + @WithDefault("50") + int age(); +} diff --git a/integration-tests/test-extension/tests/src/main/java/io/quarkus/it/extension/EnvironmentVariableTestEndpoint.java b/integration-tests/test-extension/tests/src/main/java/io/quarkus/it/extension/EnvironmentVariableTestEndpoint.java new file mode 100644 index 0000000000000..d86f22b69dd1e --- /dev/null +++ b/integration-tests/test-extension/tests/src/main/java/io/quarkus/it/extension/EnvironmentVariableTestEndpoint.java @@ -0,0 +1,20 @@ +package io.quarkus.it.extension; + +import java.io.IOException; + +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import io.quarkus.arc.Arc; + +@WebServlet(name = "EnvironmentVariableTestEndpoint", urlPatterns = "/core/env") +public class EnvironmentVariableTestEndpoint extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + DummyMapping dummyMapping = Arc.container().select(DummyMapping.class).get(); + resp.getWriter().write(dummyMapping.name() + "-" + dummyMapping.age()); + } +} diff --git a/integration-tests/test-extension/tests/src/main/resources/application.properties b/integration-tests/test-extension/tests/src/main/resources/application.properties index aabf1646bea16..7baa1d3e5898a 100644 --- a/integration-tests/test-extension/tests/src/main/resources/application.properties +++ b/integration-tests/test-extension/tests/src/main/resources/application.properties @@ -116,3 +116,5 @@ quarkus.bt.classpath-recording.resources=io/quarkus/it/extension/ClasspathTestEn quarkus.bt.classpath-recording.record-file=${project.build.directory}/classpath-entries.txt %test.quarkus.bt.classpath-recording.record-file=${project.build.directory}/classpath-entries-jvm-tests.txt quarkus.native.resources.includes=some-resource-for-classpath-test.txt + +quarkus.test.env.DUMMY_NAME=bar diff --git a/integration-tests/test-extension/tests/src/test/java/io/quarkus/it/extension/EnvVarGraalITCase.java b/integration-tests/test-extension/tests/src/test/java/io/quarkus/it/extension/EnvVarGraalITCase.java new file mode 100644 index 0000000000000..84c5ad362b9b4 --- /dev/null +++ b/integration-tests/test-extension/tests/src/test/java/io/quarkus/it/extension/EnvVarGraalITCase.java @@ -0,0 +1,18 @@ +package io.quarkus.it.extension; + +import static io.restassured.RestAssured.when; +import static org.hamcrest.Matchers.is; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusIntegrationTest; + +@QuarkusIntegrationTest +public class EnvVarGraalITCase { + + @Test + public void test() { + when().get("/core/env").then() + .body(is("bar-70")); + } +} diff --git a/integration-tests/test-extension/tests/src/test/java/io/quarkus/it/extension/EnvVarTestCase.java b/integration-tests/test-extension/tests/src/test/java/io/quarkus/it/extension/EnvVarTestCase.java new file mode 100644 index 0000000000000..b56c5f677a2be --- /dev/null +++ b/integration-tests/test-extension/tests/src/test/java/io/quarkus/it/extension/EnvVarTestCase.java @@ -0,0 +1,18 @@ +package io.quarkus.it.extension; + +import static io.restassured.RestAssured.when; +import static org.hamcrest.Matchers.is; + +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.QuarkusTest; + +@QuarkusTest +public class EnvVarTestCase { + + @Test + public void test() { + when().get("/core/env").then() + .body(is("foo-50")); + } +} diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/ArtifactLauncher.java b/test-framework/common/src/main/java/io/quarkus/test/common/ArtifactLauncher.java index 9008a935bfc2c..ba498a21a7c52 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/ArtifactLauncher.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/ArtifactLauncher.java @@ -32,6 +32,13 @@ interface InitContext { List argLine(); + /** + * Additional environment variables to be passed to the launched process. + * Note: When Quarkus launches the new process, it will always include the environment + * variables of the current process + */ + Map env(); + ArtifactLauncher.InitContext.DevServicesLaunchResult getDevServicesLaunchResult(); interface DevServicesLaunchResult extends AutoCloseable { diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/DefaultDockerContainerLauncher.java b/test-framework/common/src/main/java/io/quarkus/test/common/DefaultDockerContainerLauncher.java index ac8da95e8f883..629c90935f00f 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/DefaultDockerContainerLauncher.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/DefaultDockerContainerLauncher.java @@ -37,6 +37,7 @@ public class DefaultDockerContainerLauncher implements DockerContainerArtifactLa private long waitTimeSeconds; private String testProfile; private List argLine; + private Map env; private ArtifactLauncher.InitContext.DevServicesLaunchResult devServicesLaunchResult; private String containerImage; private boolean pullRequired; @@ -54,6 +55,7 @@ public void init(DockerContainerArtifactLauncher.DockerInitContext initContext) this.waitTimeSeconds = initContext.waitTime().getSeconds(); this.testProfile = initContext.testProfile(); this.argLine = initContext.argLine(); + this.env = initContext.env(); this.devServicesLaunchResult = initContext.getDevServicesLaunchResult(); this.containerImage = initContext.containerImage(); this.pullRequired = initContext.pullRequired(); @@ -127,9 +129,13 @@ public void start() throws IOException { args.addAll(toEnvVar("quarkus.profile", testProfile)); } - for (Map.Entry e : systemProps.entrySet()) { + for (var e : systemProps.entrySet()) { args.addAll(toEnvVar(e.getKey(), e.getValue())); } + + for (var e : env.entrySet()) { + args.addAll(envAsLaunchArg(e.getKey(), e.getValue())); + } args.add(containerImage); final Path logFile = PropertyTestUtil.getLogFilePath(); @@ -180,9 +186,13 @@ public void includeAsSysProps(Map systemProps) { this.systemProps.putAll(systemProps); } + private static List envAsLaunchArg(String name, String value) { + return List.of("--env", String.format("%s=%s", name, value)); + } + private List toEnvVar(String property, String value) { if ((property != null) && (!property.isEmpty())) { - return List.of("--env", String.format("%s=%s", convertPropertyToEnvVar(property), value)); + return envAsLaunchArg(convertPropertyToEnvVar(property), value); } return Collections.emptyList(); } diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/DefaultJarLauncher.java b/test-framework/common/src/main/java/io/quarkus/test/common/DefaultJarLauncher.java index 9b34c49bc9b8a..a038b6a492d39 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/DefaultJarLauncher.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/DefaultJarLauncher.java @@ -41,6 +41,7 @@ public class DefaultJarLauncher implements JarArtifactLauncher { private long waitTimeSeconds; private String testProfile; private List argLine; + private Map env; private Path jarPath; private final Map systemProps = new HashMap<>(); @@ -55,6 +56,7 @@ public void init(JarArtifactLauncher.JarInitContext initContext) { this.waitTimeSeconds = initContext.waitTime().getSeconds(); this.testProfile = initContext.testProfile(); this.argLine = initContext.argLine(); + this.env = initContext.env(); this.jarPath = initContext.jarPath(); } @@ -127,9 +129,9 @@ public void start(String[] programArgs, boolean handleIo) throws IOException { Files.createDirectories(logFile.getParent()); if (handleIo) { - quarkusProcess = LauncherUtil.launchProcess(args); + quarkusProcess = LauncherUtil.launchProcessAndDrainIO(args, env); } else { - quarkusProcess = Runtime.getRuntime().exec(args.toArray(new String[0])); + quarkusProcess = LauncherUtil.launchProcess(args, env); } } diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/DefaultNativeImageLauncher.java b/test-framework/common/src/main/java/io/quarkus/test/common/DefaultNativeImageLauncher.java index a4426b14c0471..fdabd340df7c8 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/DefaultNativeImageLauncher.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/DefaultNativeImageLauncher.java @@ -33,6 +33,7 @@ public class DefaultNativeImageLauncher implements NativeImageLauncher { private long waitTimeSeconds; private String testProfile; private List argLine; + private Map env; private String nativeImagePath; private String configuredOutputDirectory; private Class testClass; @@ -51,6 +52,7 @@ public void init(NativeImageInitContext initContext) { this.nativeImagePath = initContext.nativeImagePath(); this.configuredOutputDirectory = initContext.getConfiguredOutputDirectory(); this.argLine = initContext.argLine(); + this.env = initContext.env(); this.testClass = initContext.testClass(); } @@ -145,9 +147,9 @@ public void start(String[] programArgs, boolean handleIo) throws IOException { Files.deleteIfExists(logFile); Files.createDirectories(logFile.getParent()); if (handleIo) { - quarkusProcess = LauncherUtil.launchProcess(args); + quarkusProcess = LauncherUtil.launchProcessAndDrainIO(args, env); } else { - quarkusProcess = Runtime.getRuntime().exec(args.toArray(new String[0])); + quarkusProcess = LauncherUtil.launchProcess(args, env); } } diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java b/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java index 05ecb0c7d571e..08bcfb9f7f1ec 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java @@ -10,7 +10,9 @@ import java.nio.file.Path; import java.time.Duration; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.ServiceLoader; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; @@ -57,17 +59,39 @@ public static Config installAndGetSomeConfig() { * Implementation detail: Avoid using ProcessBuilder's redirect here because it causes problems with Maven Failsafe * as can be seen in here */ - static Process launchProcess(List args) throws IOException { - Process process = Runtime.getRuntime().exec(args.toArray(new String[0])); + static Process launchProcessAndDrainIO(List args, Map env) throws IOException { + Process process = launchProcess(args, env); new Thread(new ProcessReader(process.getInputStream())).start(); new Thread(new ProcessReader(process.getErrorStream())).start(); return process; } + /** + * Launches a process using the supplied arguments but does drain the IO + */ + static Process launchProcess(List args, Map env) throws IOException { + Process process; + if (env.isEmpty()) { + process = Runtime.getRuntime().exec(args.toArray(new String[0])); + } else { + Map currentEnv = System.getenv(); + Map finalEnv = new HashMap<>(currentEnv); + finalEnv.putAll(env); + String[] envArray = new String[finalEnv.size()]; + int i = 0; + for (var entry : finalEnv.entrySet()) { + envArray[i] = entry.getKey() + "=" + entry.getValue(); + i++; + } + process = Runtime.getRuntime().exec(args.toArray(new String[0]), envArray); + } + return process; + } + /** * Launches a process using the supplied arguments and makes sure the process's output is drained to standard out */ - static Process launchProcess(List args, File dir) throws IOException { + static Process launchProcessAndDrainIO(List args, File dir) throws IOException { Process process = Runtime.getRuntime().exec(args.toArray(new String[0]), null, dir); new Thread(new ProcessReader(process.getInputStream())).start(); new Thread(new ProcessReader(process.getErrorStream())).start(); diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/NativeTestExtension.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/NativeTestExtension.java index b943395a575fb..74913548a0a3c 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/NativeTestExtension.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/NativeTestExtension.java @@ -193,6 +193,7 @@ private DefaultNativeImageLauncher createLauncher(Class requiredTestClass) { ConfigUtil.waitTimeValue(config), config.getOptionalValue("quarkus.test.native-image-profile", String.class).orElse(null), ConfigUtil.argLineValue(config), + ConfigUtil.env(config), new ArtifactLauncher.InitContext.DevServicesLaunchResult() { @Override public Map properties() { diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/ConfigUtil.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/ConfigUtil.java index bb7933ce29551..a3d99b23f1b85 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/ConfigUtil.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/ConfigUtil.java @@ -6,9 +6,12 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import org.eclipse.microprofile.config.Config; +import io.smallrye.config.SmallRyeConfig; + public final class ConfigUtil { private ConfigUtil() { @@ -33,6 +36,11 @@ public static List argLineValue(Config config) { return result; } + public static Map env(Config config) { + return ((SmallRyeConfig) config).getOptionalValues("quarkus.test.env", String.class, String.class) + .orElse(Collections.emptyMap()); + } + public static Duration waitTimeValue(Config config) { return config.getOptionalValue("quarkus.test.wait-time", Duration.class) .orElseGet(() -> config.getOptionalValue("quarkus.test.jar-wait-time", Duration.class) // legacy value diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/DefaultInitContextBase.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/DefaultInitContextBase.java index dda6382d42303..7b2d2a831a0dc 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/DefaultInitContextBase.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/DefaultInitContextBase.java @@ -2,6 +2,7 @@ import java.time.Duration; import java.util.List; +import java.util.Map; import io.quarkus.test.common.ArtifactLauncher; @@ -11,15 +12,20 @@ class DefaultInitContextBase { private final Duration waitTime; private final String testProfile; private final List argLine; + + private final Map env; private final ArtifactLauncher.InitContext.DevServicesLaunchResult devServicesLaunchResult; - DefaultInitContextBase(int httpPort, int httpsPort, Duration waitTime, String testProfile, List argLine, + DefaultInitContextBase(int httpPort, int httpsPort, Duration waitTime, String testProfile, + List argLine, + Map env, ArtifactLauncher.InitContext.DevServicesLaunchResult devServicesLaunchResult) { this.httpPort = httpPort; this.httpsPort = httpsPort; this.waitTime = waitTime; this.testProfile = testProfile; this.argLine = argLine; + this.env = env; this.devServicesLaunchResult = devServicesLaunchResult; } @@ -43,6 +49,10 @@ public List argLine() { return argLine; } + public Map env() { + return env; + } + public ArtifactLauncher.InitContext.DevServicesLaunchResult getDevServicesLaunchResult() { return devServicesLaunchResult; } diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/DockerContainerLauncherProvider.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/DockerContainerLauncherProvider.java index cf898e3fa53a8..aa23e3870c588 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/DockerContainerLauncherProvider.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/DockerContainerLauncherProvider.java @@ -47,6 +47,7 @@ public DockerContainerArtifactLauncher create(CreateContext context) { ConfigUtil.waitTimeValue(config), ConfigUtil.integrationTestProfile(config), ConfigUtil.argLineValue(config), + ConfigUtil.env(config), context.devServicesLaunchResult(), containerImage, pullRequired, @@ -72,9 +73,10 @@ static class DefaultDockerInitContext extends DefaultInitContextBase private final Map additionalExposedPorts; public DefaultDockerInitContext(int httpPort, int httpsPort, Duration waitTime, String testProfile, - List argLine, ArtifactLauncher.InitContext.DevServicesLaunchResult devServicesLaunchResult, + List argLine, Map env, + ArtifactLauncher.InitContext.DevServicesLaunchResult devServicesLaunchResult, String containerImage, boolean pullRequired, Map additionalExposedPorts) { - super(httpPort, httpsPort, waitTime, testProfile, argLine, devServicesLaunchResult); + super(httpPort, httpsPort, waitTime, testProfile, argLine, env, devServicesLaunchResult); this.containerImage = containerImage; this.pullRequired = pullRequired; this.additionalExposedPorts = additionalExposedPorts; diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/JarLauncherProvider.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/JarLauncherProvider.java index ef8cde8ffcd69..75a1f7ed4d89e 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/JarLauncherProvider.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/JarLauncherProvider.java @@ -8,6 +8,7 @@ import java.time.Duration; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.OptionalInt; import java.util.ServiceLoader; @@ -45,6 +46,7 @@ public JarArtifactLauncher create(CreateContext context) { ConfigUtil.waitTimeValue(config), ConfigUtil.integrationTestProfile(config), ConfigUtil.argLineValue(config), + ConfigUtil.env(config), context.devServicesLaunchResult(), context.buildOutputDirectory().resolve(pathStr))); return launcher; @@ -57,9 +59,10 @@ static class DefaultJarInitContext extends DefaultInitContextBase implements Jar private final Path jarPath; - DefaultJarInitContext(int httpPort, int httpsPort, Duration waitTime, String testProfile, List argLine, + DefaultJarInitContext(int httpPort, int httpsPort, Duration waitTime, String testProfile, + List argLine, Map env, ArtifactLauncher.InitContext.DevServicesLaunchResult devServicesLaunchResult, Path jarPath) { - super(httpPort, httpsPort, waitTime, testProfile, argLine, devServicesLaunchResult); + super(httpPort, httpsPort, waitTime, testProfile, argLine, env, devServicesLaunchResult); this.jarPath = jarPath; } diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/NativeImageLauncherProvider.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/NativeImageLauncherProvider.java index 7b994941c9a56..f4ea8ece1921c 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/NativeImageLauncherProvider.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/NativeImageLauncherProvider.java @@ -7,6 +7,7 @@ import java.time.Duration; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.OptionalInt; import java.util.ServiceLoader; @@ -43,6 +44,7 @@ public NativeImageLauncher create(CreateContext context) { ConfigUtil.waitTimeValue(config), ConfigUtil.integrationTestProfile(config), ConfigUtil.argLineValue(config), + ConfigUtil.env(config), context.devServicesLaunchResult(), System.getProperty("native.image.path"), config.getOptionalValue("quarkus.package.output-directory", String.class).orElse(null), @@ -61,9 +63,10 @@ public static class DefaultNativeImageInitContext extends DefaultInitContextBase private final String configuredOutputDirectory; public DefaultNativeImageInitContext(int httpPort, int httpsPort, Duration waitTime, String testProfile, - List argLine, ArtifactLauncher.InitContext.DevServicesLaunchResult devServicesLaunchResult, + List argLine, Map env, + ArtifactLauncher.InitContext.DevServicesLaunchResult devServicesLaunchResult, String nativeImagePath, String configuredOutputDirectory, Class testClass) { - super(httpPort, httpsPort, waitTime, testProfile, argLine, devServicesLaunchResult); + super(httpPort, httpsPort, waitTime, testProfile, argLine, env, devServicesLaunchResult); this.nativeImagePath = nativeImagePath; this.configuredOutputDirectory = configuredOutputDirectory; this.testClass = testClass; From 817d8b061b21fa086f7c3005da17a03d114af615 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 6 Jun 2023 10:59:53 +0300 Subject: [PATCH 2/3] Remove unused method in LauncherUtil --- .../java/io/quarkus/test/common/LauncherUtil.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java b/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java index 08bcfb9f7f1ec..03a8d6566355c 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/LauncherUtil.java @@ -1,7 +1,6 @@ package io.quarkus.test.common; import java.io.BufferedReader; -import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; @@ -88,16 +87,6 @@ static Process launchProcess(List args, Map env) throws return process; } - /** - * Launches a process using the supplied arguments and makes sure the process's output is drained to standard out - */ - static Process launchProcessAndDrainIO(List args, File dir) throws IOException { - Process process = Runtime.getRuntime().exec(args.toArray(new String[0]), null, dir); - new Thread(new ProcessReader(process.getInputStream())).start(); - new Thread(new ProcessReader(process.getErrorStream())).start(); - return process; - } - /** * Waits (for a maximum of {@param waitTimeSeconds} seconds) until the launched process indicates the address it is * listening on. From d1327296bf8860350a75631040bf7cc88ff93642 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 6 Jun 2023 11:36:16 +0300 Subject: [PATCH 3/3] Add support for adding labels to containers launches with @QuarkusIntegrationTest Relates to: #33806 --- .../deployment/dev/testing/TestConfig.java | 6 +++++ .../DefaultDockerContainerLauncher.java | 8 +++++++ .../DockerContainerArtifactLauncher.java | 2 ++ .../DockerContainerLauncherProvider.java | 22 +++++++++++++++++-- 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java index 726232607ce04..5437928922eb2 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java @@ -293,6 +293,12 @@ public static class Container { */ @ConfigItem Map additionalExposedPorts; + + /** + * A set of labels to add to the launched container + */ + @ConfigItem + Map labels; } public enum Mode { diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/DefaultDockerContainerLauncher.java b/test-framework/common/src/main/java/io/quarkus/test/common/DefaultDockerContainerLauncher.java index 629c90935f00f..97ff47ccefb76 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/DefaultDockerContainerLauncher.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/DefaultDockerContainerLauncher.java @@ -42,6 +42,8 @@ public class DefaultDockerContainerLauncher implements DockerContainerArtifactLa private String containerImage; private boolean pullRequired; private Map additionalExposedPorts; + + private Map labels; private final Map systemProps = new HashMap<>(); private boolean isSsl; private final String containerName = "quarkus-integration-test-" + RandomStringUtils.random(5, true, false); @@ -60,6 +62,7 @@ public void init(DockerContainerArtifactLauncher.DockerInitContext initContext) this.containerImage = initContext.containerImage(); this.pullRequired = initContext.pullRequired(); this.additionalExposedPorts = initContext.additionalExposedPorts(); + this.labels = initContext.labels(); } @Override @@ -136,6 +139,11 @@ public void start() throws IOException { for (var e : env.entrySet()) { args.addAll(envAsLaunchArg(e.getKey(), e.getValue())); } + + for (var e : labels.entrySet()) { + args.add("--label"); + args.add(e.getKey() + "=" + e.getValue()); + } args.add(containerImage); final Path logFile = PropertyTestUtil.getLogFilePath(); diff --git a/test-framework/common/src/main/java/io/quarkus/test/common/DockerContainerArtifactLauncher.java b/test-framework/common/src/main/java/io/quarkus/test/common/DockerContainerArtifactLauncher.java index b80f682e3e9f4..97cfb81fa9c8d 100644 --- a/test-framework/common/src/main/java/io/quarkus/test/common/DockerContainerArtifactLauncher.java +++ b/test-framework/common/src/main/java/io/quarkus/test/common/DockerContainerArtifactLauncher.java @@ -11,5 +11,7 @@ interface DockerInitContext extends InitContext { boolean pullRequired(); Map additionalExposedPorts(); + + Map labels(); } } diff --git a/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/DockerContainerLauncherProvider.java b/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/DockerContainerLauncherProvider.java index aa23e3870c588..8c71c9fdc0b5b 100644 --- a/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/DockerContainerLauncherProvider.java +++ b/test-framework/junit5/src/main/java/io/quarkus/test/junit/launcher/DockerContainerLauncherProvider.java @@ -51,7 +51,8 @@ public DockerContainerArtifactLauncher create(CreateContext context) { context.devServicesLaunchResult(), containerImage, pullRequired, - additionalExposedPorts(config))); + additionalExposedPorts(config), + labels(config))); return launcher; } else { throw new IllegalStateException("The container image to be launched could not be determined"); @@ -66,20 +67,32 @@ private Map additionalExposedPorts(SmallRyeConfig config) { } } + private Map labels(SmallRyeConfig config) { + try { + return config.getValues("quarkus.test.container.labels", String.class, String.class); + } catch (NoSuchElementException e) { + return Collections.emptyMap(); + } + } + static class DefaultDockerInitContext extends DefaultInitContextBase implements DockerContainerArtifactLauncher.DockerInitContext { private final String containerImage; private final boolean pullRequired; private final Map additionalExposedPorts; + private Map labels; public DefaultDockerInitContext(int httpPort, int httpsPort, Duration waitTime, String testProfile, List argLine, Map env, ArtifactLauncher.InitContext.DevServicesLaunchResult devServicesLaunchResult, - String containerImage, boolean pullRequired, Map additionalExposedPorts) { + String containerImage, boolean pullRequired, + Map additionalExposedPorts, + Map labels) { super(httpPort, httpsPort, waitTime, testProfile, argLine, env, devServicesLaunchResult); this.containerImage = containerImage; this.pullRequired = pullRequired; this.additionalExposedPorts = additionalExposedPorts; + this.labels = labels; } @Override @@ -96,5 +109,10 @@ public boolean pullRequired() { public Map additionalExposedPorts() { return additionalExposedPorts; } + + @Override + public Map labels() { + return labels; + } } }