From 5095c06e8fc3b615073469aac05424762d1143a3 Mon Sep 17 00:00:00 2001 From: SoMuchForSubtlety Date: Sat, 3 Sep 2022 18:43:25 +0200 Subject: [PATCH 01/10] Add basic rootless podman support The implementation is mostly borrowed from the rootless docker strategy. --- .../RootlessPodmanClientProviderStrategy.java | 95 +++++++++++++++++++ ....dockerclient.DockerClientProviderStrategy | 1 + 2 files changed, 96 insertions(+) create mode 100644 core/src/main/java/org/testcontainers/dockerclient/RootlessPodmanClientProviderStrategy.java diff --git a/core/src/main/java/org/testcontainers/dockerclient/RootlessPodmanClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/RootlessPodmanClientProviderStrategy.java new file mode 100644 index 00000000000..1b11b12e6b9 --- /dev/null +++ b/core/src/main/java/org/testcontainers/dockerclient/RootlessPodmanClientProviderStrategy.java @@ -0,0 +1,95 @@ +package org.testcontainers.dockerclient; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.SystemUtils; +import org.jetbrains.annotations.Nullable; + +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Optional; + +/** + * + * @deprecated this class is used by the SPI and should not be used directly + */ +@Deprecated +@Slf4j +public final class RootlessPodmanClientProviderStrategy extends DockerClientProviderStrategy { + + public static final int PRIORITY = UnixSocketClientProviderStrategy.PRIORITY + 1; + + @Getter(lazy = true) + @Nullable + private final Path socketPath = resolveSocketPath(); + + private Path resolveSocketPath() { + return tryEnv() + .orElseGet(() -> { + Path implicitPath = Paths.get("/run/user/" + LibC.INSTANCE.getuid()); + return tryFolder(implicitPath).orElse(null); + }); + } + + private Optional tryEnv() { + String xdgRuntimeDir = System.getenv("XDG_RUNTIME_DIR"); + if (StringUtils.isBlank(xdgRuntimeDir)) { + log.debug("$XDG_RUNTIME_DIR is not set."); + return Optional.empty(); + } + Path path = Paths.get(xdgRuntimeDir); + if (!Files.exists(path)) { + log.debug("$XDG_RUNTIME_DIR is set to '{}' but the folder does not exist.", path); + return Optional.empty(); + } + Path podmanSocketPath = path.resolve("podman/podman.sock"); + if (!Files.exists(podmanSocketPath)) { + log.debug("$XDG_RUNTIME_DIR is set but '{}' does not exist.", podmanSocketPath); + return Optional.empty(); + } + return Optional.of(podmanSocketPath); + } + + private Optional tryFolder(Path path) { + if (!Files.exists(path)) { + log.debug("'{}' does not exist.", path); + return Optional.empty(); + } + Path podmanSocketPath = path.resolve("podman/podman.sock"); + if (!Files.exists(podmanSocketPath)) { + log.debug("'{}' does not exist.", podmanSocketPath); + return Optional.empty(); + } + return Optional.of(podmanSocketPath); + } + + @Override + public TransportConfig getTransportConfig() throws InvalidConfigurationException { + return TransportConfig.builder().dockerHost(URI.create("unix://" + getSocketPath().toString())).build(); + } + + @Override + protected boolean isApplicable() { + return SystemUtils.IS_OS_LINUX && getSocketPath() != null && Files.exists(getSocketPath()); + } + + @Override + public String getDescription() { + return "Rootless Podman accessed via Unix socket (" + getSocketPath() + ")"; + } + + @Override + protected int getPriority() { + return PRIORITY; + } + + private interface LibC extends Library { + LibC INSTANCE = Native.loadLibrary("c", LibC.class); + int getuid(); + } +} diff --git a/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy b/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy index cae8bf53041..cafb957db55 100644 --- a/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy +++ b/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy @@ -5,3 +5,4 @@ org.testcontainers.dockerclient.DockerMachineClientProviderStrategy org.testcontainers.dockerclient.NpipeSocketClientProviderStrategy org.testcontainers.dockerclient.RootlessDockerClientProviderStrategy org.testcontainers.dockerclient.DockerDesktopClientProviderStrategy +org.testcontainers.dockerclient.RootlessPodmanClientProviderStrategy From 7c036885eb2865b704c4a7567ca9e01cd3eb6cef Mon Sep 17 00:00:00 2001 From: SoMuchForSubtlety Date: Tue, 8 Nov 2022 19:13:17 +0100 Subject: [PATCH 02/10] add CI for podman --- .github/workflows/ci-rootless-podman.yml | 51 +++++++++++++++++++ build.gradle | 5 ++ .../testcontainers/DockerClientFactory.java | 6 +++ .../utility/TestEnvironment.java | 4 ++ .../DockerRegistryContainer.java | 6 +-- .../containers/GenericContainerTest.java | 11 +++- .../containers/NetworkTest.java | 29 ++++++++++- .../DockerHealthcheckWaitStrategyTest.java | 2 +- .../junit/DockerNetworkModeTest.java | 14 +++-- .../utility/AuthenticatedImagePullTest.java | 6 ++- .../test/java/generic/CmdModifierTest.java | 4 ++ 11 files changed, 125 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/ci-rootless-podman.yml diff --git a/.github/workflows/ci-rootless-podman.yml b/.github/workflows/ci-rootless-podman.yml new file mode 100644 index 00000000000..829b786c6c6 --- /dev/null +++ b/.github/workflows/ci-rootless-podman.yml @@ -0,0 +1,51 @@ +name: CI-Podman-Rootless + +on: + pull_request: {} + push: { branches: [ main ] } + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + - name: Uninstall unwanted packages + run: sudo apt-get -q -y --purge remove podman moby-engine moby-buildx && sudo rm -rf /var/run/docker.sock + - name: Set XDG_RUNTIME_DIR + run: echo "XDG_RUNTIME_DIR=/run/user/$UID" >> $GITHUB_ENV + - name: Create registries.conf + # allow pulling images without a registry specified and allow pulling from insecure local registry + run: | + mkdir -p $HOME/.config/containers + echo 'unqualified-search-registries = ["docker.io"]' > $HOME/.config/containers/registries.conf + echo '' >> $HOME/.config/containers/registries.conf + echo '[[registry]]' >> $HOME/.config/containers/registries.conf + echo 'location = "localhost:50001"' >> $HOME/.config/containers/registries.conf + echo 'insecure = true' >> $HOME/.config/containers/registries.conf + - name: Istall latest podman release + # see https://podman.io/getting-started/installation#ubuntu + run: | + sudo mkdir -p /etc/apt/keyrings + curl -fsSL https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(lsb_release -rs)/Release.key \ + | gpg --dearmor \ + | sudo tee /etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg > /dev/null + echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg]\ + https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(lsb_release -rs)/ /" \ + | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:unstable.list > /dev/null + sudo apt-get update -qq + sudo apt-get -qq -y install podman + - name: Print podman environment information + run: podman info + - name: Enable podman socket + run: systemctl --user enable --now podman.socket + - name: Build with Gradle + run: ./gradlew --no-daemon --scan -Dtest.profile=podman testcontainers:test + - uses: actions/upload-artifact@v3 + if: failure() + with: + name: test report + path: ~/work/testcontainers-java/testcontainers-java/core/build/reports/tests/** diff --git a/build.gradle b/build.gradle index 0acf7a82cc2..ed89f9b848f 100644 --- a/build.gradle +++ b/build.gradle @@ -94,6 +94,11 @@ subprojects { failOnPassedAfterRetry = false } } + + // podman does not support compose + if (System.properties['test.profile'] == 'podman') { + exclude '**/*DockerCompose*' + } } tasks.withType(Test).all { diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 6f0c744cedf..1508b29c6b5 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -21,6 +21,7 @@ import org.apache.commons.lang3.SystemUtils; import org.testcontainers.dockerclient.DockerClientProviderStrategy; import org.testcontainers.dockerclient.DockerMachineClientProviderStrategy; +import org.testcontainers.dockerclient.RootlessPodmanClientProviderStrategy; import org.testcontainers.dockerclient.TransportConfig; import org.testcontainers.images.RemoteDockerImage; import org.testcontainers.images.TimeLimitedLoggedPullImageResultCallback; @@ -389,4 +390,9 @@ public boolean isUsing(Class providerStr public Info getInfo() { return getOrInitializeStrategy().getInfo(); } + + public boolean supportsCompose() { + // podman does not support compose + return !(getOrInitializeStrategy() instanceof RootlessPodmanClientProviderStrategy); + } } diff --git a/core/src/main/java/org/testcontainers/utility/TestEnvironment.java b/core/src/main/java/org/testcontainers/utility/TestEnvironment.java index ee58199540b..21c4a9ffb63 100644 --- a/core/src/main/java/org/testcontainers/utility/TestEnvironment.java +++ b/core/src/main/java/org/testcontainers/utility/TestEnvironment.java @@ -17,6 +17,10 @@ public static boolean dockerApiAtLeast(String minimumVersion) { return current.compareTo(min) >= 0; } + public static boolean clientSupportsCompose() { + return DockerClientFactory.instance().supportsCompose(); + } + public static boolean dockerExecutionDriverSupportsExec() { String executionDriver = DockerClientFactory.instance().getActiveExecutionDriver(); diff --git a/core/src/test/java/org/testcontainers/DockerRegistryContainer.java b/core/src/test/java/org/testcontainers/DockerRegistryContainer.java index 956bb9fff9e..219ee02644e 100644 --- a/core/src/test/java/org/testcontainers/DockerRegistryContainer.java +++ b/core/src/test/java/org/testcontainers/DockerRegistryContainer.java @@ -37,7 +37,7 @@ public DockerRegistryContainer(@NonNull Future image) { @Override protected void configure() { super.configure(); - withEnv("REGISTRY_HTTP_ADDR", "127.0.0.1:0"); + withEnv("REGISTRY_HTTP_ADDR", "127.0.0.1:50001"); withCreateContainerCmdModifier(cmd -> { cmd.getHostConfig().withNetworkMode("host"); }); @@ -77,7 +77,7 @@ protected void containerIsStarting(InspectContainerResponse containerInfo) { ); } - endpoint = getHost() + ":" + port.get(); + endpoint = "http://" + getHost() + ":" + port.get(); } public DockerImageName createImage() { @@ -96,7 +96,7 @@ public DockerImageName createImage(String originalImage, String tag) { String dummyImageId = client.inspectImageCmd(originalImage).exec().getId(); DockerImageName imageName = DockerImageName - .parse(getEndpoint() + "/" + Base58.randomString(6).toLowerCase()) + .parse(getEndpoint().replaceFirst("http://", "") + "/" + Base58.randomString(6).toLowerCase()) .withTag(tag); // push the image to the registry diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index fb0b216bce2..74a51adbc43 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -27,6 +27,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -43,6 +44,8 @@ public void shouldReportOOMAfterWait() { Info info = DockerClientFactory.instance().client().infoCmd().exec(); // Poor man's rootless Docker detection :D Assumptions.assumeThat(info.getSecurityOptions()).doesNotContain("rootless"); + // setting swappiness is not allowed for cgroups v2 + Assumptions.assumeThat(info.getRawValues().get("CgroupVersion")).isNotEqualTo("2"); try ( GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withStartupCheckStrategy(new NoopStartupCheckStrategy()) @@ -154,7 +157,13 @@ public void shouldOnlyPublishExposedPorts() { .getHostConfig() .getPortBindings() .getBindings(); - assertThat(hostBindings).as("only 1 port is bound on the host (published)").hasSize(1); + // podman also returns unbound ports, but sets the binding value to null + List boundPorts = hostBindings + .values() + .stream() + .filter(Objects::nonNull) + .collect(Collectors.toList()); + assertThat(boundPorts).as("only 1 port is bound on the host (published)").hasSize(1); Integer mappedPort = container.getMappedPort(8080); assertThat(mappedPort != 8080).as("port 8080 is bound to a different port on the host").isTrue(); diff --git a/core/src/test/java/org/testcontainers/containers/NetworkTest.java b/core/src/test/java/org/testcontainers/containers/NetworkTest.java index 099bef20ed7..cbf06baf066 100644 --- a/core/src/test/java/org/testcontainers/containers/NetworkTest.java +++ b/core/src/test/java/org/testcontainers/containers/NetworkTest.java @@ -1,5 +1,6 @@ package org.testcontainers.containers; +import com.github.dockerjava.api.model.Network.Ipam; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.runners.Enclosed; @@ -65,7 +66,19 @@ public void testNetworkSupport() throws Exception { @Test public void testBuilder() { - try (Network network = Network.builder().driver("macvlan").build()) { + try ( + Network network = Network + .builder() + .driver("macvlan") + .createNetworkCmdModifier(cmd -> { + cmd.withIpam( + // mcvlan needs a subnet or podman will refuse to create the network + // https://docs.podman.io/en/latest/markdown/podman-network-create.1.html#driver-d + new Ipam().withConfig(new Ipam.Config().withSubnet("192.168.100.1/25")) + ); + }) + .build() + ) { String id = network.getId(); assertThat( DockerClientFactory.instance().client().inspectNetworkCmd().withNetworkId(id).exec().getDriver() @@ -78,7 +91,19 @@ public void testBuilder() { @Test public void testModifiers() { try ( - Network network = Network.builder().createNetworkCmdModifier(cmd -> cmd.withDriver("macvlan")).build() + Network network = Network + .builder() + .createNetworkCmdModifier(cmd -> { + cmd + .withDriver("macvlan") + .withIpam( + new Ipam() + // mcvlan needs a subnet or podman will refuse to create the network + // https://docs.podman.io/en/latest/markdown/podman-network-create.1.html#driver-d + .withConfig(new Ipam.Config().withSubnet("192.168.100.1/25")) + ); + }) + .build() ) { String id = network.getId(); assertThat( diff --git a/core/src/test/java/org/testcontainers/containers/wait/strategy/DockerHealthcheckWaitStrategyTest.java b/core/src/test/java/org/testcontainers/containers/wait/strategy/DockerHealthcheckWaitStrategyTest.java index 0cbf257e9b5..7ef82f28079 100644 --- a/core/src/test/java/org/testcontainers/containers/wait/strategy/DockerHealthcheckWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/containers/wait/strategy/DockerHealthcheckWaitStrategyTest.java @@ -27,7 +27,7 @@ public void setUp() { ) .withFileFromClasspath("Dockerfile", "health-wait-strategy-dockerfile/Dockerfile") ) - .waitingFor(Wait.forHealthcheck().withStartupTimeout(Duration.ofSeconds(3))); + .waitingFor(Wait.forHealthcheck().withStartupTimeout(Duration.ofSeconds(5))); } @Test diff --git a/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java b/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java index b048e4716fd..97aafb80bdb 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java @@ -27,8 +27,11 @@ public void testNoNetworkContainer() { container.start(); NetworkSettings networkSettings = container.getContainerInfo().getNetworkSettings(); - assertThat(networkSettings.getNetworks()).as("only one network is set").hasSize(1); - assertThat(networkSettings.getNetworks()).as("network is 'none'").containsKey("none"); + assertThat(networkSettings.getNetworks()) + .as("only one network is set") + .allSatisfy((name, containerNetwork) -> { + assertThat(name).as("network is 'none'").isEqualTo("none"); + }); } } @@ -43,8 +46,11 @@ public void testHostNetworkContainer() { container.start(); NetworkSettings networkSettings = container.getContainerInfo().getNetworkSettings(); - assertThat(networkSettings.getNetworks()).as("only one network is set").hasSize(1); - assertThat(networkSettings.getNetworks()).as("network is 'host'").containsKey("host"); + assertThat(networkSettings.getNetworks()) + .as("only one network is set") + .allSatisfy((name, containerNetwork) -> { + assertThat(networkSettings.getNetworks()).as("network is 'host'").containsKey("host"); + }); } } } diff --git a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java index 0e00dd87bf7..21ba4fe7e34 100644 --- a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java +++ b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java @@ -3,6 +3,7 @@ import com.github.dockerjava.api.model.AuthConfig; import org.intellij.lang.annotations.Language; import org.junit.AfterClass; +import org.junit.Assume; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; @@ -63,14 +64,14 @@ public static void beforeClass() throws Exception { final AuthConfig authConfig = new AuthConfig() .withUsername("testuser") .withPassword("notasecret") - .withRegistryAddress("http://" + testRegistryAddress); + .withRegistryAddress(testRegistryAddress); // Replace the RegistryAuthLocator singleton with our mock, for the duration of this test final RegistryAuthLocator mockAuthLocator = Mockito.mock(RegistryAuthLocator.class); RegistryAuthLocator.setInstance(mockAuthLocator); when( mockAuthLocator.lookupAuthConfig( - argThat(argument -> testRegistryAddress.equals(argument.getRegistry())), + argThat(argument -> testRegistryAddress.replaceFirst("http://", "").equals(argument.getRegistry())), any() ) ) @@ -117,6 +118,7 @@ public void testThatAuthLocatorIsUsedForDockerfileBuild() throws IOException { @Test public void testThatAuthLocatorIsUsedForDockerComposePull() throws IOException { + Assume.assumeTrue(TestEnvironment.clientSupportsCompose()); // Prepare a simple temporary Docker Compose manifest which requires our custom private image Path tempFile = getLocalTempFile(".docker-compose.yml"); @Language("yaml") diff --git a/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java b/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java index a8ace490d82..35934109b41 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java @@ -2,6 +2,7 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.model.Info; +import org.assertj.core.api.Assumptions; import org.junit.Rule; import org.junit.Test; import org.testcontainers.DockerClientFactory; @@ -48,6 +49,9 @@ public void testHostnameModified() throws IOException, InterruptedException { @Test public void testMemoryLimitModified() throws IOException, InterruptedException { + Info info = DockerClientFactory.instance().client().infoCmd().exec(); + // setting swap is not allowed for cgroups v2 + Assumptions.assumeThat(info.getRawValues().get("CgroupVersion")).isNotEqualTo("2"); final Container.ExecResult execResult = memoryLimitedRedis.execInContainer("cat", getMemoryLimitFilePath()); assertThat(execResult.getStdout().trim()).isEqualTo(String.valueOf(memoryInBytes)); } From fc17f0e9264404b41266ec234ee99ef83cc8e68e Mon Sep 17 00:00:00 2001 From: SoMuchForSubtlety Date: Wed, 9 Nov 2022 16:24:22 +0100 Subject: [PATCH 03/10] revert test changes --- .github/workflows/ci-rootless-podman.yml | 8 ++--- build.gradle | 16 +++++++++- .../testcontainers/DockerClientFactory.java | 6 ---- .../utility/TestEnvironment.java | 4 --- .../DockerRegistryContainer.java | 8 ++--- .../containers/GenericContainerTest.java | 11 +------ .../containers/NetworkTest.java | 29 ++----------------- .../DockerHealthcheckWaitStrategyTest.java | 2 +- .../junit/DockerNetworkModeTest.java | 14 +++------ .../utility/AuthenticatedImagePullTest.java | 6 ++-- .../test/java/generic/CmdModifierTest.java | 4 --- 11 files changed, 31 insertions(+), 77 deletions(-) diff --git a/.github/workflows/ci-rootless-podman.yml b/.github/workflows/ci-rootless-podman.yml index 829b786c6c6..8966897f856 100644 --- a/.github/workflows/ci-rootless-podman.yml +++ b/.github/workflows/ci-rootless-podman.yml @@ -17,15 +17,11 @@ jobs: - name: Set XDG_RUNTIME_DIR run: echo "XDG_RUNTIME_DIR=/run/user/$UID" >> $GITHUB_ENV - name: Create registries.conf - # allow pulling images without a registry specified and allow pulling from insecure local registry + # allow pulling images without a registry specified run: | mkdir -p $HOME/.config/containers echo 'unqualified-search-registries = ["docker.io"]' > $HOME/.config/containers/registries.conf - echo '' >> $HOME/.config/containers/registries.conf - echo '[[registry]]' >> $HOME/.config/containers/registries.conf - echo 'location = "localhost:50001"' >> $HOME/.config/containers/registries.conf - echo 'insecure = true' >> $HOME/.config/containers/registries.conf - - name: Istall latest podman release + - name: Install latest podman release # see https://podman.io/getting-started/installation#ubuntu run: | sudo mkdir -p /etc/apt/keyrings diff --git a/build.gradle b/build.gradle index ed89f9b848f..bf9c67d58c1 100644 --- a/build.gradle +++ b/build.gradle @@ -95,9 +95,23 @@ subprojects { } } - // podman does not support compose if (System.properties['test.profile'] == 'podman') { exclude '**/*DockerCompose*' + filter { + excludeTestsMatching '*AuthenticatedImagePullTest*' + excludeTestsMatching '*DockerNetworkModeTest*' + excludeTestsMatching '*AmbiguousImagePullTest*' + excludeTestsMatching '*ImagePullPolicyTest*' + + excludeTestsMatching '*testThatAuthLocatorIsUsedForDockerComposePull' + excludeTestsMatching '*testMemoryLimitModified' + excludeTestsMatching '*testBuilder' + excludeTestsMatching '*testModifiers' + excludeTestsMatching '*shouldOnlyPublishExposedPorts' + excludeTestsMatching '*shouldReportOOMAfterWait' + excludeTestsMatching '*runCommandInsideDockerShouldNotFailIfImageDoesNotExistsLocally' + } + } } diff --git a/core/src/main/java/org/testcontainers/DockerClientFactory.java b/core/src/main/java/org/testcontainers/DockerClientFactory.java index 1508b29c6b5..6f0c744cedf 100644 --- a/core/src/main/java/org/testcontainers/DockerClientFactory.java +++ b/core/src/main/java/org/testcontainers/DockerClientFactory.java @@ -21,7 +21,6 @@ import org.apache.commons.lang3.SystemUtils; import org.testcontainers.dockerclient.DockerClientProviderStrategy; import org.testcontainers.dockerclient.DockerMachineClientProviderStrategy; -import org.testcontainers.dockerclient.RootlessPodmanClientProviderStrategy; import org.testcontainers.dockerclient.TransportConfig; import org.testcontainers.images.RemoteDockerImage; import org.testcontainers.images.TimeLimitedLoggedPullImageResultCallback; @@ -390,9 +389,4 @@ public boolean isUsing(Class providerStr public Info getInfo() { return getOrInitializeStrategy().getInfo(); } - - public boolean supportsCompose() { - // podman does not support compose - return !(getOrInitializeStrategy() instanceof RootlessPodmanClientProviderStrategy); - } } diff --git a/core/src/main/java/org/testcontainers/utility/TestEnvironment.java b/core/src/main/java/org/testcontainers/utility/TestEnvironment.java index 21c4a9ffb63..ee58199540b 100644 --- a/core/src/main/java/org/testcontainers/utility/TestEnvironment.java +++ b/core/src/main/java/org/testcontainers/utility/TestEnvironment.java @@ -17,10 +17,6 @@ public static boolean dockerApiAtLeast(String minimumVersion) { return current.compareTo(min) >= 0; } - public static boolean clientSupportsCompose() { - return DockerClientFactory.instance().supportsCompose(); - } - public static boolean dockerExecutionDriverSupportsExec() { String executionDriver = DockerClientFactory.instance().getActiveExecutionDriver(); diff --git a/core/src/test/java/org/testcontainers/DockerRegistryContainer.java b/core/src/test/java/org/testcontainers/DockerRegistryContainer.java index 219ee02644e..a907c674386 100644 --- a/core/src/test/java/org/testcontainers/DockerRegistryContainer.java +++ b/core/src/test/java/org/testcontainers/DockerRegistryContainer.java @@ -37,7 +37,7 @@ public DockerRegistryContainer(@NonNull Future image) { @Override protected void configure() { super.configure(); - withEnv("REGISTRY_HTTP_ADDR", "127.0.0.1:50001"); + withEnv("REGISTRY_HTTP_ADDR", "127.0.0.1:0"); withCreateContainerCmdModifier(cmd -> { cmd.getHostConfig().withNetworkMode("host"); }); @@ -77,7 +77,7 @@ protected void containerIsStarting(InspectContainerResponse containerInfo) { ); } - endpoint = "http://" + getHost() + ":" + port.get(); + endpoint = getHost() + ":" + port.get(); } public DockerImageName createImage() { @@ -96,11 +96,11 @@ public DockerImageName createImage(String originalImage, String tag) { String dummyImageId = client.inspectImageCmd(originalImage).exec().getId(); DockerImageName imageName = DockerImageName - .parse(getEndpoint().replaceFirst("http://", "") + "/" + Base58.randomString(6).toLowerCase()) + .parse(getEndpoint() + "/" + Base58.randomString(6).toLowerCase()) .withTag(tag); // push the image to the registry - client.tagImageCmd(dummyImageId, imageName.getUnversionedPart(), tag).exec(); + client.tagImageCmd(dummyImageId, imageName.asCanonicalNameString(), tag).exec(); client .pushImageCmd(imageName.asCanonicalNameString()) diff --git a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java index 74a51adbc43..fb0b216bce2 100644 --- a/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java +++ b/core/src/test/java/org/testcontainers/containers/GenericContainerTest.java @@ -27,7 +27,6 @@ import java.util.Arrays; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -44,8 +43,6 @@ public void shouldReportOOMAfterWait() { Info info = DockerClientFactory.instance().client().infoCmd().exec(); // Poor man's rootless Docker detection :D Assumptions.assumeThat(info.getSecurityOptions()).doesNotContain("rootless"); - // setting swappiness is not allowed for cgroups v2 - Assumptions.assumeThat(info.getRawValues().get("CgroupVersion")).isNotEqualTo("2"); try ( GenericContainer container = new GenericContainer<>(TestImages.TINY_IMAGE) .withStartupCheckStrategy(new NoopStartupCheckStrategy()) @@ -157,13 +154,7 @@ public void shouldOnlyPublishExposedPorts() { .getHostConfig() .getPortBindings() .getBindings(); - // podman also returns unbound ports, but sets the binding value to null - List boundPorts = hostBindings - .values() - .stream() - .filter(Objects::nonNull) - .collect(Collectors.toList()); - assertThat(boundPorts).as("only 1 port is bound on the host (published)").hasSize(1); + assertThat(hostBindings).as("only 1 port is bound on the host (published)").hasSize(1); Integer mappedPort = container.getMappedPort(8080); assertThat(mappedPort != 8080).as("port 8080 is bound to a different port on the host").isTrue(); diff --git a/core/src/test/java/org/testcontainers/containers/NetworkTest.java b/core/src/test/java/org/testcontainers/containers/NetworkTest.java index cbf06baf066..099bef20ed7 100644 --- a/core/src/test/java/org/testcontainers/containers/NetworkTest.java +++ b/core/src/test/java/org/testcontainers/containers/NetworkTest.java @@ -1,6 +1,5 @@ package org.testcontainers.containers; -import com.github.dockerjava.api.model.Network.Ipam; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.runners.Enclosed; @@ -66,19 +65,7 @@ public void testNetworkSupport() throws Exception { @Test public void testBuilder() { - try ( - Network network = Network - .builder() - .driver("macvlan") - .createNetworkCmdModifier(cmd -> { - cmd.withIpam( - // mcvlan needs a subnet or podman will refuse to create the network - // https://docs.podman.io/en/latest/markdown/podman-network-create.1.html#driver-d - new Ipam().withConfig(new Ipam.Config().withSubnet("192.168.100.1/25")) - ); - }) - .build() - ) { + try (Network network = Network.builder().driver("macvlan").build()) { String id = network.getId(); assertThat( DockerClientFactory.instance().client().inspectNetworkCmd().withNetworkId(id).exec().getDriver() @@ -91,19 +78,7 @@ public void testBuilder() { @Test public void testModifiers() { try ( - Network network = Network - .builder() - .createNetworkCmdModifier(cmd -> { - cmd - .withDriver("macvlan") - .withIpam( - new Ipam() - // mcvlan needs a subnet or podman will refuse to create the network - // https://docs.podman.io/en/latest/markdown/podman-network-create.1.html#driver-d - .withConfig(new Ipam.Config().withSubnet("192.168.100.1/25")) - ); - }) - .build() + Network network = Network.builder().createNetworkCmdModifier(cmd -> cmd.withDriver("macvlan")).build() ) { String id = network.getId(); assertThat( diff --git a/core/src/test/java/org/testcontainers/containers/wait/strategy/DockerHealthcheckWaitStrategyTest.java b/core/src/test/java/org/testcontainers/containers/wait/strategy/DockerHealthcheckWaitStrategyTest.java index 7ef82f28079..0cbf257e9b5 100644 --- a/core/src/test/java/org/testcontainers/containers/wait/strategy/DockerHealthcheckWaitStrategyTest.java +++ b/core/src/test/java/org/testcontainers/containers/wait/strategy/DockerHealthcheckWaitStrategyTest.java @@ -27,7 +27,7 @@ public void setUp() { ) .withFileFromClasspath("Dockerfile", "health-wait-strategy-dockerfile/Dockerfile") ) - .waitingFor(Wait.forHealthcheck().withStartupTimeout(Duration.ofSeconds(5))); + .waitingFor(Wait.forHealthcheck().withStartupTimeout(Duration.ofSeconds(3))); } @Test diff --git a/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java b/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java index 97aafb80bdb..b048e4716fd 100644 --- a/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java +++ b/core/src/test/java/org/testcontainers/junit/DockerNetworkModeTest.java @@ -27,11 +27,8 @@ public void testNoNetworkContainer() { container.start(); NetworkSettings networkSettings = container.getContainerInfo().getNetworkSettings(); - assertThat(networkSettings.getNetworks()) - .as("only one network is set") - .allSatisfy((name, containerNetwork) -> { - assertThat(name).as("network is 'none'").isEqualTo("none"); - }); + assertThat(networkSettings.getNetworks()).as("only one network is set").hasSize(1); + assertThat(networkSettings.getNetworks()).as("network is 'none'").containsKey("none"); } } @@ -46,11 +43,8 @@ public void testHostNetworkContainer() { container.start(); NetworkSettings networkSettings = container.getContainerInfo().getNetworkSettings(); - assertThat(networkSettings.getNetworks()) - .as("only one network is set") - .allSatisfy((name, containerNetwork) -> { - assertThat(networkSettings.getNetworks()).as("network is 'host'").containsKey("host"); - }); + assertThat(networkSettings.getNetworks()).as("only one network is set").hasSize(1); + assertThat(networkSettings.getNetworks()).as("network is 'host'").containsKey("host"); } } } diff --git a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java index 21ba4fe7e34..0e00dd87bf7 100644 --- a/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java +++ b/core/src/test/java/org/testcontainers/utility/AuthenticatedImagePullTest.java @@ -3,7 +3,6 @@ import com.github.dockerjava.api.model.AuthConfig; import org.intellij.lang.annotations.Language; import org.junit.AfterClass; -import org.junit.Assume; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Test; @@ -64,14 +63,14 @@ public static void beforeClass() throws Exception { final AuthConfig authConfig = new AuthConfig() .withUsername("testuser") .withPassword("notasecret") - .withRegistryAddress(testRegistryAddress); + .withRegistryAddress("http://" + testRegistryAddress); // Replace the RegistryAuthLocator singleton with our mock, for the duration of this test final RegistryAuthLocator mockAuthLocator = Mockito.mock(RegistryAuthLocator.class); RegistryAuthLocator.setInstance(mockAuthLocator); when( mockAuthLocator.lookupAuthConfig( - argThat(argument -> testRegistryAddress.replaceFirst("http://", "").equals(argument.getRegistry())), + argThat(argument -> testRegistryAddress.equals(argument.getRegistry())), any() ) ) @@ -118,7 +117,6 @@ public void testThatAuthLocatorIsUsedForDockerfileBuild() throws IOException { @Test public void testThatAuthLocatorIsUsedForDockerComposePull() throws IOException { - Assume.assumeTrue(TestEnvironment.clientSupportsCompose()); // Prepare a simple temporary Docker Compose manifest which requires our custom private image Path tempFile = getLocalTempFile(".docker-compose.yml"); @Language("yaml") diff --git a/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java b/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java index 35934109b41..a8ace490d82 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java +++ b/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java @@ -2,7 +2,6 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.model.Info; -import org.assertj.core.api.Assumptions; import org.junit.Rule; import org.junit.Test; import org.testcontainers.DockerClientFactory; @@ -49,9 +48,6 @@ public void testHostnameModified() throws IOException, InterruptedException { @Test public void testMemoryLimitModified() throws IOException, InterruptedException { - Info info = DockerClientFactory.instance().client().infoCmd().exec(); - // setting swap is not allowed for cgroups v2 - Assumptions.assumeThat(info.getRawValues().get("CgroupVersion")).isNotEqualTo("2"); final Container.ExecResult execResult = memoryLimitedRedis.execInContainer("cat", getMemoryLimitFilePath()); assertThat(execResult.getStdout().trim()).isEqualTo(String.valueOf(memoryInBytes)); } From 74b2586eba05e01053e5158f66663bd933b1e409 Mon Sep 17 00:00:00 2001 From: SoMuchForSubtlety Date: Mon, 12 Dec 2022 17:22:30 +0100 Subject: [PATCH 04/10] allow insecure connections to localhost see https://github.com/containers/podman/issues/16486#issuecomment-1344132137 --- .github/workflows/ci-rootless-podman.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-rootless-podman.yml b/.github/workflows/ci-rootless-podman.yml index 8966897f856..38c66784343 100644 --- a/.github/workflows/ci-rootless-podman.yml +++ b/.github/workflows/ci-rootless-podman.yml @@ -16,11 +16,15 @@ jobs: run: sudo apt-get -q -y --purge remove podman moby-engine moby-buildx && sudo rm -rf /var/run/docker.sock - name: Set XDG_RUNTIME_DIR run: echo "XDG_RUNTIME_DIR=/run/user/$UID" >> $GITHUB_ENV - - name: Create registries.conf - # allow pulling images without a registry specified + - name: Configure podman run: | mkdir -p $HOME/.config/containers echo 'unqualified-search-registries = ["docker.io"]' > $HOME/.config/containers/registries.conf + echo '' >> $HOME/.config/containers/registries.conf + echo '[[registry]]' >> $HOME/.config/containers/registries.conf + echo 'prefix = "localhost"' >> $HOME/.config/containers/registries.conf + echo 'location = "localhost"' >> $HOME/.config/containers/registries.conf + echo 'insecure = true' >> $HOME/.config/containers/registries.conf - name: Install latest podman release # see https://podman.io/getting-started/installation#ubuntu run: | From b9be20558207b2f3b24520161dbffe91bdf71080 Mon Sep 17 00:00:00 2001 From: SoMuchForSubtlety Date: Fri, 16 Dec 2022 11:18:56 +0100 Subject: [PATCH 05/10] re-enable some tests --- build.gradle | 8 +------- .../java/org/testcontainers/DockerRegistryContainer.java | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index bf9c67d58c1..0788595d808 100644 --- a/build.gradle +++ b/build.gradle @@ -98,18 +98,12 @@ subprojects { if (System.properties['test.profile'] == 'podman') { exclude '**/*DockerCompose*' filter { - excludeTestsMatching '*AuthenticatedImagePullTest*' excludeTestsMatching '*DockerNetworkModeTest*' - excludeTestsMatching '*AmbiguousImagePullTest*' - excludeTestsMatching '*ImagePullPolicyTest*' - excludeTestsMatching '*testThatAuthLocatorIsUsedForDockerComposePull' - excludeTestsMatching '*testMemoryLimitModified' excludeTestsMatching '*testBuilder' excludeTestsMatching '*testModifiers' - excludeTestsMatching '*shouldOnlyPublishExposedPorts' + excludeTestsMatching '*shouldReportOOMAfterWait' - excludeTestsMatching '*runCommandInsideDockerShouldNotFailIfImageDoesNotExistsLocally' } } diff --git a/core/src/test/java/org/testcontainers/DockerRegistryContainer.java b/core/src/test/java/org/testcontainers/DockerRegistryContainer.java index a907c674386..956bb9fff9e 100644 --- a/core/src/test/java/org/testcontainers/DockerRegistryContainer.java +++ b/core/src/test/java/org/testcontainers/DockerRegistryContainer.java @@ -100,7 +100,7 @@ public DockerImageName createImage(String originalImage, String tag) { .withTag(tag); // push the image to the registry - client.tagImageCmd(dummyImageId, imageName.asCanonicalNameString(), tag).exec(); + client.tagImageCmd(dummyImageId, imageName.getUnversionedPart(), tag).exec(); client .pushImageCmd(imageName.asCanonicalNameString()) From 9825a5700696d2b69f8ee021c5eb23a6ac285f51 Mon Sep 17 00:00:00 2001 From: SoMuchForSubtlety Date: Mon, 3 Apr 2023 19:19:50 +0200 Subject: [PATCH 06/10] enable all tests --- build.gradle | 9 --------- 1 file changed, 9 deletions(-) diff --git a/build.gradle b/build.gradle index 0788595d808..319304e8cd9 100644 --- a/build.gradle +++ b/build.gradle @@ -97,15 +97,6 @@ subprojects { if (System.properties['test.profile'] == 'podman') { exclude '**/*DockerCompose*' - filter { - excludeTestsMatching '*DockerNetworkModeTest*' - - excludeTestsMatching '*testBuilder' - excludeTestsMatching '*testModifiers' - - excludeTestsMatching '*shouldReportOOMAfterWait' - } - } } From 4dd54b549910b623d63f87d507beff9947cecb61 Mon Sep 17 00:00:00 2001 From: SoMuchForSubtlety Date: Fri, 14 Apr 2023 19:07:50 +0200 Subject: [PATCH 07/10] Add comments to gradle config --- build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build.gradle b/build.gradle index 319304e8cd9..69d46440103 100644 --- a/build.gradle +++ b/build.gradle @@ -96,7 +96,12 @@ subprojects { } if (System.properties['test.profile'] == 'podman') { + // The compose container relies on the deprecated link feature, which is not supported by podman exclude '**/*DockerCompose*' + filter { + // cgroups v2 don't support settings swappiness + excludeTestsMatching '*shouldReportOOMAfterWait' + } } } From 376820448c47bd8cea0830f311c22492fe9a34f5 Mon Sep 17 00:00:00 2001 From: SoMuchForSubtlety Date: Fri, 14 Apr 2023 22:53:56 +0200 Subject: [PATCH 08/10] Decrease priority of podman strategy --- .../dockerclient/RootlessPodmanClientProviderStrategy.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/testcontainers/dockerclient/RootlessPodmanClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/RootlessPodmanClientProviderStrategy.java index 1b11b12e6b9..1473adc5234 100644 --- a/core/src/main/java/org/testcontainers/dockerclient/RootlessPodmanClientProviderStrategy.java +++ b/core/src/main/java/org/testcontainers/dockerclient/RootlessPodmanClientProviderStrategy.java @@ -22,7 +22,7 @@ @Slf4j public final class RootlessPodmanClientProviderStrategy extends DockerClientProviderStrategy { - public static final int PRIORITY = UnixSocketClientProviderStrategy.PRIORITY + 1; + public static final int PRIORITY = UnixSocketClientProviderStrategy.PRIORITY - 1; @Getter(lazy = true) @Nullable From de7011eb22889c5770ff3a78fbd8f3eb26442367 Mon Sep 17 00:00:00 2001 From: SoMuchForSubtlety Date: Wed, 31 May 2023 20:34:19 +0200 Subject: [PATCH 09/10] Simplify CI --- .github/workflows/ci-rootless-podman.yml | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ci-rootless-podman.yml b/.github/workflows/ci-rootless-podman.yml index 38c66784343..87ae296aef5 100644 --- a/.github/workflows/ci-rootless-podman.yml +++ b/.github/workflows/ci-rootless-podman.yml @@ -13,9 +13,8 @@ jobs: steps: - uses: actions/checkout@v3 - name: Uninstall unwanted packages + # docker would be preferred over podman run: sudo apt-get -q -y --purge remove podman moby-engine moby-buildx && sudo rm -rf /var/run/docker.sock - - name: Set XDG_RUNTIME_DIR - run: echo "XDG_RUNTIME_DIR=/run/user/$UID" >> $GITHUB_ENV - name: Configure podman run: | mkdir -p $HOME/.config/containers @@ -28,24 +27,10 @@ jobs: - name: Install latest podman release # see https://podman.io/getting-started/installation#ubuntu run: | - sudo mkdir -p /etc/apt/keyrings - curl -fsSL https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(lsb_release -rs)/Release.key \ - | gpg --dearmor \ - | sudo tee /etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg > /dev/null - echo \ - "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg]\ - https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(lsb_release -rs)/ /" \ - | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:unstable.list > /dev/null + curl -fsSL https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(lsb_release -rs)/Release.key | gpg --dearmor | sudo tee /etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg > /dev/null + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg] https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(lsb_release -rs)/ /" | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:unstable.list > /dev/null sudo apt-get update -qq sudo apt-get -qq -y install podman - - name: Print podman environment information - run: podman info - - name: Enable podman socket - run: systemctl --user enable --now podman.socket + systemctl --user enable --now podman.socket - name: Build with Gradle run: ./gradlew --no-daemon --scan -Dtest.profile=podman testcontainers:test - - uses: actions/upload-artifact@v3 - if: failure() - with: - name: test report - path: ~/work/testcontainers-java/testcontainers-java/core/build/reports/tests/** From 945bc17d78f3d7c401d27d9d93fef1d35a196ca1 Mon Sep 17 00:00:00 2001 From: SoMuchForSubtlety Date: Wed, 31 May 2023 21:25:02 +0200 Subject: [PATCH 10/10] Simplify config The unqualified registries setting is no longer needed, see https://github.com/containers/podman/pull/12435 --- .github/workflows/ci-rootless-podman.yml | 12 +++++------- build.gradle | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci-rootless-podman.yml b/.github/workflows/ci-rootless-podman.yml index 87ae296aef5..4d270cbfbc7 100644 --- a/.github/workflows/ci-rootless-podman.yml +++ b/.github/workflows/ci-rootless-podman.yml @@ -2,7 +2,7 @@ name: CI-Podman-Rootless on: pull_request: {} - push: { branches: [ main ] } + push: { branches: [main] } permissions: contents: read @@ -18,12 +18,10 @@ jobs: - name: Configure podman run: | mkdir -p $HOME/.config/containers - echo 'unqualified-search-registries = ["docker.io"]' > $HOME/.config/containers/registries.conf - echo '' >> $HOME/.config/containers/registries.conf - echo '[[registry]]' >> $HOME/.config/containers/registries.conf - echo 'prefix = "localhost"' >> $HOME/.config/containers/registries.conf - echo 'location = "localhost"' >> $HOME/.config/containers/registries.conf - echo 'insecure = true' >> $HOME/.config/containers/registries.conf + echo '[[registry]]' > $HOME/.config/containers/registries.conf + echo 'prefix = "localhost"' >> $HOME/.config/containers/registries.conf + echo 'location = "localhost"' >> $HOME/.config/containers/registries.conf + echo 'insecure = true' >> $HOME/.config/containers/registries.conf - name: Install latest podman release # see https://podman.io/getting-started/installation#ubuntu run: | diff --git a/build.gradle b/build.gradle index 69d46440103..afc436f8594 100644 --- a/build.gradle +++ b/build.gradle @@ -97,7 +97,7 @@ subprojects { if (System.properties['test.profile'] == 'podman') { // The compose container relies on the deprecated link feature, which is not supported by podman - exclude '**/*DockerCompose*' + exclude '**/*Compose*' filter { // cgroups v2 don't support settings swappiness excludeTestsMatching '*shouldReportOOMAfterWait'