diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e3b79f4..6a8c2a95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Please enumerate all user-facing changes using format `: ## 0.8.0 +* [#248](https://github.com/kroxylicious/kroxylicious-junit5-extension/issues/248): Allow user to bring their own test templating when using KafkaClusterExtension * [#244](https://github.com/kroxylicious/kroxylicious-junit5-extension/pull/244): Bump org.testcontainers:testcontainers-bom from 1.19.2 to 1.19.3 ## 0.7.0 diff --git a/junit5-extension/src/main/java/io/kroxylicious/testing/kafka/junit5ext/KafkaClusterExtension.java b/junit5-extension/src/main/java/io/kroxylicious/testing/kafka/junit5ext/KafkaClusterExtension.java index c4ebfe47..402dc997 100644 --- a/junit5-extension/src/main/java/io/kroxylicious/testing/kafka/junit5ext/KafkaClusterExtension.java +++ b/junit5-extension/src/main/java/io/kroxylicious/testing/kafka/junit5ext/KafkaClusterExtension.java @@ -7,6 +7,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Executable; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Parameter; @@ -458,8 +459,13 @@ public void close() throws Throwable { @Override public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { - return !parameterContext.getDeclaringExecutable().isAnnotationPresent(TestTemplate.class) - && supportsParameter(parameterContext.getParameter()); + return !hasTestTemplateConfiguration(parameterContext.getDeclaringExecutable()) && supportsParameter(parameterContext.getParameter()); + } + + private boolean hasTestTemplateConfiguration(Executable executable) { + return executable.isAnnotationPresent(TestTemplate.class) + && Arrays.stream(executable.getParameters()).anyMatch( + p -> p.getAnnotationsByType(DimensionMethodSource.class).length > 0 || p.getAnnotationsByType(ConstraintsMethodSource.class).length > 0); } @Override diff --git a/junit5-extension/src/test/java/io/kroxylicious/testing/kafka/junit5ext/TemplateTest.java b/junit5-extension/src/test/java/io/kroxylicious/testing/kafka/junit5ext/TemplateTest.java index 50cd4d19..98b8231d 100644 --- a/junit5-extension/src/test/java/io/kroxylicious/testing/kafka/junit5ext/TemplateTest.java +++ b/junit5-extension/src/test/java/io/kroxylicious/testing/kafka/junit5ext/TemplateTest.java @@ -11,6 +11,7 @@ import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -18,11 +19,19 @@ import org.apache.kafka.clients.admin.Config; import org.apache.kafka.common.config.ConfigResource; import org.apache.kafka.common.errors.UnsupportedVersionException; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.Extension; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.ParameterContext; +import org.junit.jupiter.api.extension.ParameterResolutionException; +import org.junit.jupiter.api.extension.TestTemplateInvocationContext; +import org.junit.jupiter.api.extension.TestTemplateInvocationContextProvider; +import org.junit.jupiter.api.extension.support.TypeBasedParameterResolver; import io.kroxylicious.testing.kafka.api.KafkaCluster; import io.kroxylicious.testing.kafka.common.BrokerCluster; @@ -43,6 +52,7 @@ @ExtendWith(KafkaClusterExtension.class) public class TemplateTest { + @SuppressWarnings("unused") static Stream clusterSizes() { return Stream.of( brokerCluster(1), @@ -65,11 +75,13 @@ public void testMultipleClusterSizesWithAdminParameters(@DimensionMethodSource(v assertThat(admin.describeCluster().nodes().get()).hasSize(cluster.getNumOfBrokers()); } - static Set> observedCartesianProduct = new HashSet<>(); - @Nested @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class CartesianProduct { + + private final Set> observedCartesianProduct = new HashSet<>(); + + @SuppressWarnings("unused") static Stream compression() { return Stream.of( brokerConfig("compression.type", "zstd"), @@ -110,6 +122,7 @@ public void afterAll() { } } + @SuppressWarnings("unused") static Stream> tuples() { return Stream.of( List.of(brokerCluster(1), kraftCluster(1)), @@ -117,11 +130,10 @@ static Stream> tuples() { List.of(brokerCluster(3), zooKeeperCluster())); } - static Set> observedTuples = new HashSet<>(); - @Nested @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class Tuples { + private final Set> observedTuples = new HashSet<>(); @TestTemplate public void testTuples(@ConstraintsMethodSource(value = "tuples", clazz = TemplateTest.class) KafkaCluster cluster, @@ -166,12 +178,12 @@ private static Stream versions() { version("3.1.2")); } - static Set observedVersions = new HashSet<>(); - @Nested @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class Versions { + private final Set observedVersions = new HashSet<>(); + @TestTemplate public void testVersions(@DimensionMethodSource(value = "versions", clazz = TemplateTest.class) @KRaftCluster TestcontainersKafkaCluster cluster) { observedVersions.add(cluster.getKafkaVersion()); @@ -182,4 +194,73 @@ public void afterAll() { assertThat(observedVersions).isEqualTo(versions().map(Version::value).collect(Collectors.toSet())); } } + + @Nested + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + public class CooperationWithAnotherTestTemplateInvocationContextProvider { + private final AtomicInteger observedInvocations = new AtomicInteger(); + private final Set observedResolvedParams = new HashSet<>(); + + @TestTemplate + @ExtendWith(MyTestTemplateInvocationContextProvider.class) + void invocation(KafkaCluster cluster) { + assertThat(cluster).isNotNull(); + observedInvocations.incrementAndGet(); + } + + @TestTemplate + @ExtendWith(MyTestTemplateInvocationContextProvider.class) + void invocationWithResolvedParameter(KafkaCluster cluster, MyTestParam testParam) { + assertThat(cluster).isNotNull(); + observedResolvedParams.add(testParam); + } + + @AfterAll + void afterAll() { + assertThat(observedInvocations).hasValue(2); + assertThat(observedResolvedParams).containsExactly(new MyTestParam("one"), new MyTestParam("two")); + } + + } + + private record MyTestParam(String value) { + } + + private static class MyTestTemplateInvocationContextProvider implements TestTemplateInvocationContextProvider { + @Override + public boolean supportsTestTemplate(ExtensionContext context) { + return true; + } + + @Override + public Stream provideTestTemplateInvocationContexts(ExtensionContext context) { + return Stream.of( + getTestTemplateInvocationContext("one"), + getTestTemplateInvocationContext("two")); + } + + @NotNull + private TestTemplateInvocationContext getTestTemplateInvocationContext(String value) { + return new TestTemplateInvocationContext() { + @Override + public String getDisplayName(int invocationIndex) { + return value; + } + + @Override + public List getAdditionalExtensions() { + return List.of( + new TypeBasedParameterResolver() { + + @Override + public MyTestParam resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) + throws ParameterResolutionException { + return new MyTestParam(value); + } + }); + } + + }; + } + } }