Skip to content

Commit

Permalink
introduce 'EnabledIfDockerAvailable' junit-jupiter conditional (testc…
Browse files Browse the repository at this point in the history
  • Loading branch information
eidottermihi committed May 16, 2024
1 parent 18ea976 commit 3bb8b24
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.testcontainers.junit.jupiter;

import org.testcontainers.DockerClientFactory;

class DockerAvailableDetector {

public boolean isDockerAvailable() {
try {
DockerClientFactory.instance().client();
return true;
} catch (Throwable ex) {
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.testcontainers.junit.jupiter;

import org.junit.jupiter.api.extension.ExtendWith;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* {@code EnabledIfDockerAvailable} is a JUnit Jupiter extension to enable tests only if Docker is available.
*/
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ExtendWith(EnabledIfDockerAvailableCondition.class)
public @interface EnabledIfDockerAvailable {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.testcontainers.junit.jupiter;

import org.junit.jupiter.api.extension.ConditionEvaluationResult;
import org.junit.jupiter.api.extension.ExecutionCondition;
import org.junit.jupiter.api.extension.ExtensionConfigurationException;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.platform.commons.support.AnnotationSupport;

import java.util.Optional;

public class EnabledIfDockerAvailableCondition implements ExecutionCondition {

private final DockerAvailableDetector dockerDetector = new DockerAvailableDetector();

@Override
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
return findAnnotation(context)
.map(this::evaluate)
.orElseThrow(() -> new ExtensionConfigurationException("@EnabledIfDockerAvailable not found"));
}

boolean isDockerAvailable() {
return dockerDetector.isDockerAvailable();
}

private ConditionEvaluationResult evaluate(EnabledIfDockerAvailable testcontainers) {
if (isDockerAvailable()) {
return ConditionEvaluationResult.enabled("Docker is available");
}
return ConditionEvaluationResult.disabled("Docker is not available");
}

private Optional<EnabledIfDockerAvailable> findAnnotation(ExtensionContext context) {
Optional<ExtensionContext> current = Optional.of(context);
while (current.isPresent()) {
Optional<EnabledIfDockerAvailable> enabledIfDockerAvailable = AnnotationSupport.findAnnotation(
current.get().getRequiredTestClass(),
EnabledIfDockerAvailable.class
);
if (enabledIfDockerAvailable.isPresent()) {
return enabledIfDockerAvailable;
}
current = current.get().getParent();
}
return Optional.empty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import org.junit.platform.commons.support.HierarchyTraversalMode;
import org.junit.platform.commons.support.ModifierSupport;
import org.junit.platform.commons.support.ReflectionSupport;
import org.testcontainers.DockerClientFactory;
import org.testcontainers.lifecycle.Startable;
import org.testcontainers.lifecycle.Startables;
import org.testcontainers.lifecycle.TestDescription;
Expand All @@ -42,6 +41,8 @@ public class TestcontainersExtension

private static final String LOCAL_LIFECYCLE_AWARE_CONTAINERS = "localLifecycleAwareContainers";

private final DockerAvailableDetector dockerDetector = new DockerAvailableDetector();

@Override
public void beforeAll(ExtensionContext context) {
Class<?> testClass = context
Expand Down Expand Up @@ -192,12 +193,7 @@ private ConditionEvaluationResult evaluate(Testcontainers testcontainers) {
}

boolean isDockerAvailable() {
try {
DockerClientFactory.instance().client();
return true;
} catch (Throwable ex) {
return false;
}
return dockerDetector.isDockerAvailable();
}

private Set<Object> collectParentTestInstances(final ExtensionContext context) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.testcontainers.junit.jupiter;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
import org.junit.jupiter.api.extension.ExtensionContext;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class EnabledIfDockerAvailableTests {

@Test
void whenDockerIsAvailableTestsAreEnabled() {
ConditionEvaluationResult result = new TestEnabledIfDockerAvailableCondition(true)
.evaluateExecutionCondition(extensionContext(DisabledWithoutDocker.class));
assertThat(result.isDisabled()).isFalse();
}

@Test
void whenDockerIsUnavailableTestsAreDisabled() {
ConditionEvaluationResult result = new TestEnabledIfDockerAvailableCondition(false)
.evaluateExecutionCondition(extensionContext(DisabledWithoutDocker.class));
assertThat(result.isDisabled()).isTrue();
}

private ExtensionContext extensionContext(Class clazz) {
ExtensionContext extensionContext = mock(ExtensionContext.class);
when(extensionContext.getRequiredTestClass()).thenReturn(clazz);
return extensionContext;
}

@EnabledIfDockerAvailable
static final class DisabledWithoutDocker {}

static final class TestEnabledIfDockerAvailableCondition extends EnabledIfDockerAvailableCondition {

private final boolean dockerAvailable;

private TestEnabledIfDockerAvailableCondition(boolean dockerAvailable) {
this.dockerAvailable = dockerAvailable;
}

boolean isDockerAvailable() {
return dockerAvailable;
}
}
}

0 comments on commit 3bb8b24

Please sign in to comment.