-
Notifications
You must be signed in to change notification settings - Fork 139
feat: add Docker/Podman test utilities for conditional test execution #740
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| # Docker Test Utilities | ||
|
|
||
| JUnit 5 utilities for conditional execution of Docker/Podman-based tests. | ||
|
|
||
| ## Overview | ||
|
|
||
| This module provides a `@RequiresDocker` annotation that conditionally executes tests based on Docker or Podman availability and user preferences. It automatically checks for both Docker and Podman container engines. | ||
|
|
||
| ## Usage | ||
|
|
||
| Add the dependency to your test module: | ||
|
|
||
| ```xml | ||
| <dependency> | ||
| <groupId>io.github.a2asdk</groupId> | ||
| <artifactId>a2a-java-test-utils-docker</artifactId> | ||
| <scope>test</scope> | ||
| </dependency> | ||
| ``` | ||
|
|
||
| Annotate test classes that require Docker: | ||
|
|
||
| ```java | ||
| import io.a2a.testutils.docker.RequiresDocker; | ||
| import io.quarkus.test.junit.QuarkusTest; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| @QuarkusTest | ||
| @RequiresDocker | ||
| public class MyDockerBasedTest { | ||
|
|
||
| @Test | ||
| public void testSomethingWithDocker() { | ||
| // Test that requires Docker (e.g., Testcontainers, Quarkus Dev Services) | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Behavior | ||
|
|
||
| | `-DskipDockerTests` | Docker/Podman Available | Behavior | | ||
| |---------------------|------------------------|----------| | ||
| | Not set | ✅ Yes | **RUN** tests normally | | ||
| | Not set | ❌ No | **ABORT** tests with error message | | ||
| | `true` | ✅ Yes | **SKIP** tests (shown as disabled) | | ||
| | `true` | ❌ No | **SKIP** tests (shown as disabled) | | ||
|
|
||
| ## Examples | ||
|
|
||
| ### Run all tests (requires Docker to be running) | ||
| ```bash | ||
| mvn clean install | ||
| ``` | ||
|
|
||
| ### Skip Docker tests when Docker is not available | ||
| ```bash | ||
| mvn clean install -DskipDockerTests=true | ||
| ``` | ||
|
|
||
| ### Expected behavior when Docker is NOT available | ||
|
|
||
| **Without skip flag:** | ||
| ```bash | ||
| mvn clean install | ||
| # Tests ABORT with: "Docker/Podman is not available. Use -DskipDockerTests=true to skip these tests." | ||
| ``` | ||
|
|
||
| **With skip flag:** | ||
| ```bash | ||
| mvn clean install -DskipDockerTests=true | ||
| # Tests are SKIPPED, build succeeds | ||
| # Modules still compile | ||
| ``` | ||
|
|
||
| ## Implementation Details | ||
|
|
||
| - **Container Detection**: Checks for both `docker` and `podman` commands by executing `docker info` or `podman info` | ||
| - **JUnit 5 Extension**: Implements `ExecutionCondition` to control test execution | ||
| - **Class-Level Only**: Annotation is applied at the class level (not method level) | ||
| - **Compilation**: Modules are always compiled regardless of Docker/Podman availability or skip flag | ||
| - **No External Dependencies**: Uses only Java standard library for container detection (no Testcontainers dependency) | ||
|
|
||
| ## Use Cases | ||
|
|
||
| This is useful for: | ||
| - **CI/CD pipelines** where Docker/Podman may not be available | ||
| - **Local development** when container daemon is not running | ||
| - **Quarkus Dev Services** tests that automatically start containers | ||
| - **Testcontainers-based** integration tests | ||
| - **Podman users** who use Podman instead of Docker |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | ||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
|
|
||
| <parent> | ||
| <groupId>io.github.a2asdk</groupId> | ||
| <artifactId>a2a-java-sdk-parent</artifactId> | ||
| <version>1.0.0.Alpha4-SNAPSHOT</version> | ||
| <relativePath>../pom.xml</relativePath> | ||
| </parent> | ||
|
|
||
| <artifactId>a2a-java-test-utils-docker</artifactId> | ||
| <name>A2A Java SDK :: Test Utils :: Docker</name> | ||
| <description>Test utilities for conditional Docker-based test execution</description> | ||
|
|
||
| <dependencies> | ||
| <!-- JUnit 5 for the extension - provided scope (consumer provides) --> | ||
| <dependency> | ||
| <groupId>org.junit.jupiter</groupId> | ||
| <artifactId>junit-jupiter-api</artifactId> | ||
| <scope>provided</scope> | ||
| </dependency> | ||
|
|
||
| <!-- SLF4J for logging - provided scope (consumer provides) --> | ||
| <dependency> | ||
| <groupId>org.slf4j</groupId> | ||
| <artifactId>slf4j-api</artifactId> | ||
| <scope>provided</scope> | ||
| </dependency> | ||
| </dependencies> | ||
| </project> |
91 changes: 91 additions & 0 deletions
91
test-utils-docker/src/main/java/io/a2a/testutils/docker/DockerAvailability.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| package io.a2a.testutils.docker; | ||
|
|
||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| import java.io.IOException; | ||
| import java.util.concurrent.TimeUnit; | ||
|
|
||
| /** | ||
| * Utility class for checking Docker/Podman availability and test skip settings. | ||
| */ | ||
| public final class DockerAvailability { | ||
|
|
||
| private static final Logger LOG = LoggerFactory.getLogger(DockerAvailability.class); | ||
| private static final String SKIP_DOCKER_TESTS_PROPERTY = "skipDockerTests"; | ||
|
|
||
| private static volatile Boolean dockerAvailable = null; | ||
|
|
||
| private DockerAvailability() { | ||
| // Utility class | ||
| } | ||
|
|
||
| /** | ||
| * Checks if Docker or Podman is available in the current environment. | ||
| * The result is cached after the first check. | ||
| * | ||
| * @return true if Docker or Podman is available, false otherwise | ||
| */ | ||
| public static boolean isDockerAvailable() { | ||
| if (dockerAvailable == null) { | ||
| synchronized (DockerAvailability.class) { | ||
| if (dockerAvailable == null) { | ||
| dockerAvailable = checkDockerAvailable(); | ||
| } | ||
| } | ||
| } | ||
| return dockerAvailable; | ||
| } | ||
kabir marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /** | ||
| * Checks if Docker tests should be skipped based on the system property. | ||
| * Tests are skipped when the system property "skipDockerTests" is set to "true". | ||
| * | ||
| * @return true if Docker tests should be skipped, false otherwise | ||
| */ | ||
| public static boolean shouldSkipDockerTests() { | ||
| return Boolean.parseBoolean(System.getProperty(SKIP_DOCKER_TESTS_PROPERTY, "false")); | ||
| } | ||
|
|
||
| private static boolean checkDockerAvailable() { | ||
| // Try docker first, then podman | ||
| if (tryContainerCommand("docker")) { | ||
| LOG.info("Docker is available"); | ||
| return true; | ||
| } | ||
|
|
||
| if (tryContainerCommand("podman")) { | ||
| LOG.info("Podman is available"); | ||
| return true; | ||
| } | ||
|
|
||
| LOG.warn("Neither Docker nor Podman is available"); | ||
| return false; | ||
| } | ||
|
|
||
| private static boolean tryContainerCommand(String command) { | ||
| try { | ||
| Process process = new ProcessBuilder(command, "info") | ||
| .redirectOutput(ProcessBuilder.Redirect.DISCARD) | ||
| .redirectError(ProcessBuilder.Redirect.DISCARD) | ||
| .start(); | ||
|
|
||
| boolean finished = process.waitFor(5, TimeUnit.SECONDS); | ||
| if (!finished) { | ||
| LOG.debug("Timeout waiting for '{} info' command, destroying process", command); | ||
| process.destroyForcibly(); | ||
| return false; | ||
| } | ||
|
|
||
| int exitCode = process.exitValue(); | ||
| return exitCode == 0; | ||
| } catch (IOException e) { | ||
| LOG.debug("Failed to execute '{} info' command", command, e); | ||
| return false; | ||
| } catch (InterruptedException e) { | ||
| Thread.currentThread().interrupt(); | ||
| LOG.debug("Interrupted while waiting for '{} info' command", command, e); | ||
| return false; | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.