From 7db0293db4e4a6018447bb747e80847c81252166 Mon Sep 17 00:00:00 2001 From: "sebastian.zahrhuber" Date: Tue, 3 Dec 2024 10:27:35 +0100 Subject: [PATCH 1/3] feat: added interception of parameterized tests to Junit OpenFeature Extension Signed-off-by: sebastian.zahrhuber --- .../OpenFeatureExtension.java | 29 ++++++++++++++----- .../junitopenfeature/BooleanFlagTest.java | 28 ++++++++++++++++++ .../junitopenfeature/DoubleFlagTest.java | 28 ++++++++++++++++++ .../junitopenfeature/IntegerFlagTest.java | 28 ++++++++++++++++++ .../junitopenfeature/StringFlagTest.java | 28 ++++++++++++++++++ 5 files changed, 133 insertions(+), 8 deletions(-) diff --git a/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/OpenFeatureExtension.java b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/OpenFeatureExtension.java index 1c271131d..51239bcd3 100644 --- a/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/OpenFeatureExtension.java +++ b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/OpenFeatureExtension.java @@ -3,11 +3,7 @@ import dev.openfeature.sdk.OpenFeatureAPI; import dev.openfeature.sdk.providers.memory.Flag; import org.apache.commons.lang3.BooleanUtils; -import org.junit.jupiter.api.extension.AfterEachCallback; -import org.junit.jupiter.api.extension.BeforeEachCallback; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.InvocationInterceptor; -import org.junit.jupiter.api.extension.ReflectiveInvocationContext; +import org.junit.jupiter.api.extension.*; import org.junitpioneer.internal.PioneerAnnotationUtils; import java.lang.reflect.Method; @@ -97,9 +93,15 @@ public void interceptTestMethod( ReflectiveInvocationContext invocationContext, ExtensionContext extensionContext ) throws Throwable { - TestProvider.setCurrentNamespace(getNamespace(extensionContext)); - invocation.proceed(); - TestProvider.clearCurrentNamespace(); + executeWithNamespace(invocation, extensionContext); + } + + @Override + public void interceptTestTemplateMethod( + Invocation invocation, + ReflectiveInvocationContext invocationContext, + ExtensionContext extensionContext) throws Throwable { + executeWithNamespace(invocation, extensionContext); } @Override @@ -150,4 +152,15 @@ private ExtensionContext.Namespace getNamespace(ExtensionContext extensionContex private ExtensionContext.Store getStore(ExtensionContext context) { return context.getStore(ExtensionContext.Namespace.create(getClass())); } + + private void executeWithNamespace( + Invocation invocation, + ExtensionContext extensionContext) throws Throwable { + TestProvider.setCurrentNamespace(getNamespace(extensionContext)); + try { + invocation.proceed(); + } finally { + TestProvider.clearCurrentNamespace(); + } + } } diff --git a/tools/junit-openfeature/src/test/java/dev/openfeature/contrib/tools/junitopenfeature/BooleanFlagTest.java b/tools/junit-openfeature/src/test/java/dev/openfeature/contrib/tools/junitopenfeature/BooleanFlagTest.java index 37b6e01ea..d62b6ac98 100644 --- a/tools/junit-openfeature/src/test/java/dev/openfeature/contrib/tools/junitopenfeature/BooleanFlagTest.java +++ b/tools/junit-openfeature/src/test/java/dev/openfeature/contrib/tools/junitopenfeature/BooleanFlagTest.java @@ -4,6 +4,8 @@ import dev.openfeature.sdk.OpenFeatureAPI; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import static org.assertj.core.api.Assertions.assertThat; @@ -45,6 +47,14 @@ void multipleFlagsSimple() { assertThat(client.getBooleanValue(FLAG + "2", false)).isTrue(); assertThat(client.getBooleanValue(FLAG + "3", false)).isTrue(); } + + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @Flag(name = FLAG, value = "true") + void existingSimpleFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getBooleanValue(FLAG, false)).isTrue(); + } } @Nested @@ -81,6 +91,14 @@ void multipleFlagsSimple() { assertThat(client.getBooleanValue(FLAG + "2", false)).isTrue(); assertThat(client.getBooleanValue(FLAG + "3", false)).isTrue(); } + + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @Flag(name = FLAG, value = "true") + void existingSimpleFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient("testSpecific"); + assertThat(client.getBooleanValue(FLAG, false)).isTrue(); + } } @Nested @@ -125,6 +143,16 @@ void multipleFlags() { assertThat(client.getBooleanValue(FLAG + "3", false)).isTrue(); } + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @OpenFeature({ + @Flag(name = FLAG, value = "true") + }) + void existingFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getBooleanValue(FLAG, false)).isTrue(); + } + @Nested @OpenFeature({ @Flag(name = FLAG, value = "true"), diff --git a/tools/junit-openfeature/src/test/java/dev/openfeature/contrib/tools/junitopenfeature/DoubleFlagTest.java b/tools/junit-openfeature/src/test/java/dev/openfeature/contrib/tools/junitopenfeature/DoubleFlagTest.java index 34a0fc6d5..ee56a01b1 100644 --- a/tools/junit-openfeature/src/test/java/dev/openfeature/contrib/tools/junitopenfeature/DoubleFlagTest.java +++ b/tools/junit-openfeature/src/test/java/dev/openfeature/contrib/tools/junitopenfeature/DoubleFlagTest.java @@ -4,6 +4,8 @@ import dev.openfeature.sdk.OpenFeatureAPI; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import static org.assertj.core.api.Assertions.assertThat; @@ -52,6 +54,14 @@ void multipleFlagsSimple() { assertThat(client.getDoubleValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); } } + + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Double.class) + void existingSimpleFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } } @Nested @@ -88,6 +98,14 @@ void multipleFlagsSimple() { assertThat(client.getDoubleValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); } } + + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Double.class) + void existingSimpleFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); + assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } } @Nested @@ -132,6 +150,16 @@ void multipleFlags() { assertThat(client.getDoubleValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); } + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @OpenFeature({ + @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Double.class) + }) + void existingFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Nested @OpenFeature({ @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Double.class), diff --git a/tools/junit-openfeature/src/test/java/dev/openfeature/contrib/tools/junitopenfeature/IntegerFlagTest.java b/tools/junit-openfeature/src/test/java/dev/openfeature/contrib/tools/junitopenfeature/IntegerFlagTest.java index b658ff7c1..cb74090b1 100644 --- a/tools/junit-openfeature/src/test/java/dev/openfeature/contrib/tools/junitopenfeature/IntegerFlagTest.java +++ b/tools/junit-openfeature/src/test/java/dev/openfeature/contrib/tools/junitopenfeature/IntegerFlagTest.java @@ -4,6 +4,8 @@ import dev.openfeature.sdk.OpenFeatureAPI; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import static org.assertj.core.api.Assertions.assertThat; @@ -52,6 +54,14 @@ void multipleFlagsSimple() { assertThat(client.getIntegerValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); } } + + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Integer.class) + void existingSimpleFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } } @Nested @@ -88,6 +98,14 @@ void multipleFlagsSimple() { assertThat(client.getIntegerValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); } } + + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Integer.class) + void existingSimpleFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); + assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } } @Nested @@ -132,6 +150,16 @@ void multipleFlags() { assertThat(client.getIntegerValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); } + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @OpenFeature({ + @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Integer.class) + }) + void existingSimpleFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Nested @OpenFeature({ @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Integer.class), diff --git a/tools/junit-openfeature/src/test/java/dev/openfeature/contrib/tools/junitopenfeature/StringFlagTest.java b/tools/junit-openfeature/src/test/java/dev/openfeature/contrib/tools/junitopenfeature/StringFlagTest.java index 1d463426f..b30a6b092 100644 --- a/tools/junit-openfeature/src/test/java/dev/openfeature/contrib/tools/junitopenfeature/StringFlagTest.java +++ b/tools/junit-openfeature/src/test/java/dev/openfeature/contrib/tools/junitopenfeature/StringFlagTest.java @@ -4,6 +4,8 @@ import dev.openfeature.sdk.OpenFeatureAPI; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import static org.assertj.core.api.Assertions.assertThat; @@ -50,6 +52,14 @@ void multipleFlagsSimple() { assertThat(client.getStringValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getStringValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); } + + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @Flag(name = FLAG, value = FLAG_VALUE, valueType = String.class) + void existingSimpleFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } } @Nested @@ -86,6 +96,14 @@ void multipleFlagsSimple() { assertThat(client.getStringValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getStringValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); } + + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @Flag(name = FLAG, value = FLAG_VALUE, valueType = String.class) + void existingSimpleFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); + assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } } @Nested @@ -130,6 +148,16 @@ void multipleFlags() { assertThat(client.getStringValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); } + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @OpenFeature({ + @Flag(name = FLAG , value = FLAG_VALUE, valueType = String.class) + }) + void existingSimpleFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Nested @OpenFeature({ @Flag(name = FLAG , value = FLAG_VALUE, valueType = String.class), From dab33996d15534375c314a4d64808404b71863e9 Mon Sep 17 00:00:00 2001 From: "sebastian.zahrhuber" Date: Tue, 3 Dec 2024 10:50:58 +0100 Subject: [PATCH 2/3] feat: reverted wildcard import Signed-off-by: sebastian.zahrhuber --- .../tools/junitopenfeature/OpenFeatureExtension.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/OpenFeatureExtension.java b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/OpenFeatureExtension.java index 51239bcd3..00f8bb82b 100644 --- a/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/OpenFeatureExtension.java +++ b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/OpenFeatureExtension.java @@ -3,7 +3,11 @@ import dev.openfeature.sdk.OpenFeatureAPI; import dev.openfeature.sdk.providers.memory.Flag; import org.apache.commons.lang3.BooleanUtils; -import org.junit.jupiter.api.extension.*; +import org.junit.jupiter.api.extension.AfterEachCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.api.extension.InvocationInterceptor; +import org.junit.jupiter.api.extension.ReflectiveInvocationContext; import org.junitpioneer.internal.PioneerAnnotationUtils; import java.lang.reflect.Method; From 26099bcf62bd2fd2807a52562ccaf1d7dd14c396 Mon Sep 17 00:00:00 2001 From: "sebastian.zahrhuber" Date: Tue, 3 Dec 2024 10:59:28 +0100 Subject: [PATCH 3/3] feat: added note to README Signed-off-by: sebastian.zahrhuber --- tools/junit-openfeature/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/junit-openfeature/README.md b/tools/junit-openfeature/README.md index 0b43b056d..876158f11 100644 --- a/tools/junit-openfeature/README.md +++ b/tools/junit-openfeature/README.md @@ -16,7 +16,8 @@ A JUnit5 extension to reduce boilerplate code for testing code which utilizes Op ## Getting Started -We are supporting two different flavors for testing, a [simple](#simple-configuration) and an [extended](#extended-configuration) configuration. +- We are supporting two different flavors for testing, a [simple](#simple-configuration) and an [extended](#extended-configuration) configuration. +- Both the [`@Test`](https://junit.org/junit5/docs/5.9.0/api/org.junit.jupiter.api/org/junit/jupiter/api/Test.html) annotation and the [`@ParameterizedTest`](https://junit.org/junit5/docs/5.9.0/api/org.junit.jupiter.params/org/junit/jupiter/params/ParameterizedTest.html) annotation are supported. Notice: We are most likely not multithread compatible! ### Simple Configuration