diff --git a/tools/junit-openfeature/pom.xml b/tools/junit-openfeature/pom.xml index 1f2349437..b0c13d076 100644 --- a/tools/junit-openfeature/pom.xml +++ b/tools/junit-openfeature/pom.xml @@ -37,6 +37,11 @@ junit-jupiter-api + + org.junit.platform + junit-platform-testkit + + org.junit-pioneer junit-pioneer diff --git a/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/BooleanFlag.java b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/BooleanFlag.java new file mode 100755 index 000000000..ea0b00dd3 --- /dev/null +++ b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/BooleanFlag.java @@ -0,0 +1,28 @@ +package dev.openfeature.contrib.tools.junitopenfeature; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + +/** + * Repeatable annotation that allows you to define boolean feature flags for the default domain. + * Can be used as a standalone flag configuration but also within {@link OpenFeature}. + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Repeatable(BooleanFlags.class) +@ExtendWith(OpenFeatureExtension.class) +public @interface BooleanFlag { + /** + * The key of the FeatureFlag. + */ + String name(); + + /** + * The value of the FeatureFlag. + */ + boolean value(); +} diff --git a/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/BooleanFlags.java b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/BooleanFlags.java new file mode 100755 index 000000000..42a3c9f80 --- /dev/null +++ b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/BooleanFlags.java @@ -0,0 +1,20 @@ +package dev.openfeature.contrib.tools.junitopenfeature; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + +/** + * Collection of {@link BooleanFlag} configurations. + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(OpenFeatureExtension.class) +public @interface BooleanFlags { + /** + * Collection of {@link BooleanFlag} configurations. + */ + BooleanFlag[] value() default {}; +} diff --git a/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/DoubleFlag.java b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/DoubleFlag.java new file mode 100755 index 000000000..2adfa139c --- /dev/null +++ b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/DoubleFlag.java @@ -0,0 +1,27 @@ +package dev.openfeature.contrib.tools.junitopenfeature; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + +/** + * Repeatable annotation that allows you to define double feature flags for the default domain. + * Can be used as a standalone flag configuration but also within {@link OpenFeature}. + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Repeatable(DoubleFlags.class) +@ExtendWith(OpenFeatureExtension.class) +public @interface DoubleFlag { + /** + * The key of the FeatureFlag. + */ + String name(); + /** + * The value of the FeatureFlag. + */ + double value(); +} diff --git a/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/DoubleFlags.java b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/DoubleFlags.java new file mode 100755 index 000000000..7eeb3def6 --- /dev/null +++ b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/DoubleFlags.java @@ -0,0 +1,20 @@ +package dev.openfeature.contrib.tools.junitopenfeature; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + +/** + * Collection of {@link DoubleFlag} configurations. + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(OpenFeatureExtension.class) +public @interface DoubleFlags { + /** + * Collection of {@link DoubleFlag} configurations. + */ + DoubleFlag[] value() default {}; +} diff --git a/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/IntegerFlag.java b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/IntegerFlag.java new file mode 100755 index 000000000..10cc182c8 --- /dev/null +++ b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/IntegerFlag.java @@ -0,0 +1,27 @@ +package dev.openfeature.contrib.tools.junitopenfeature; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + +/** + * Repeatable annotation that allows you to define integer feature flags for the default domain. + * Can be used as a standalone flag configuration but also within {@link OpenFeature}. + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Repeatable(IntegerFlags.class) +@ExtendWith(OpenFeatureExtension.class) +public @interface IntegerFlag { + /** + * The key of the FeatureFlag. + */ + String name(); + /** + * The value of the FeatureFlag. + */ + int value(); +} diff --git a/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/IntegerFlags.java b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/IntegerFlags.java new file mode 100755 index 000000000..71e73ec6e --- /dev/null +++ b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/IntegerFlags.java @@ -0,0 +1,20 @@ +package dev.openfeature.contrib.tools.junitopenfeature; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + +/** + * Collection of {@link IntegerFlag} configurations. + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(OpenFeatureExtension.class) +public @interface IntegerFlags { + /** + * Collection of {@link IntegerFlag} configurations. + */ + IntegerFlag[] value() default {}; +} diff --git a/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/OpenFeature.java b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/OpenFeature.java index 2e7ab0586..fe5dcfd43 100644 --- a/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/OpenFeature.java +++ b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/OpenFeature.java @@ -10,6 +10,11 @@ /** * Annotation for generating an extended configuration for OpenFeature. * This annotation allows you to specify a list of flags for a specific domain. + *

+ * Flags with duplicate names across different flag arrays + * (e.g., in {@link OpenFeature#value()} and {@link OpenFeature#booleanFlags()} + * or {@link OpenFeature#booleanFlags()} and {@link OpenFeature#stringFlags()}) + * are not permitted and will result in an {@link IllegalArgumentException}. */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @@ -23,5 +28,21 @@ /** * Collection of {@link Flag} configurations for this domain. */ - Flag[] value(); + Flag[] value() default {}; + /** + * Collection of {@link BooleanFlag} configurations for this domain. + */ + BooleanFlag[] booleanFlags() default {}; + /** + * Collection of {@link StringFlag} configurations for this domain. + */ + StringFlag[] stringFlags() default {}; + /** + * Collection of {@link IntegerFlag} configurations for this domain. + */ + IntegerFlag[] integerFlags() default {}; + /** + * Collection of {@link DoubleFlag} configurations for this domain. + */ + DoubleFlag[] doubleFlags() default {}; } 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 cebf5e6b0..01429580a 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,9 +3,15 @@ import dev.openfeature.sdk.OpenFeatureAPI; import dev.openfeature.sdk.providers.memory.Flag; import java.lang.reflect.Method; +import java.util.AbstractMap; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.lang3.BooleanUtils; import org.junit.jupiter.api.extension.AfterEachCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; @@ -23,37 +29,127 @@ public class OpenFeatureExtension implements BeforeEachCallback, AfterEachCallba private static Map>> handleExtendedConfiguration( ExtensionContext extensionContext, Map>> configuration) { - PioneerAnnotationUtils.findAllEnclosingRepeatableAnnotations(extensionContext, OpenFeature.class) - .forEachOrdered(annotation -> { - Map> domainFlags = configuration.getOrDefault(annotation.domain(), new HashMap<>()); - - Arrays.stream(annotation.value()) - .filter(flag -> !domainFlags.containsKey(flag.name())) - .forEach(flag -> { - Flag.FlagBuilder builder = generateFlagBuilder(flag); - domainFlags.put(flag.name(), builder.build()); - }); - configuration.put(annotation.domain(), domainFlags); - }); + List openFeatureAnnotationList = PioneerAnnotationUtils.findAllEnclosingRepeatableAnnotations( + extensionContext, OpenFeature.class) + .collect(Collectors.toList()); + Map> nonTypedFlagNamesByDomain = getFlagNamesByDomain(openFeatureAnnotationList); + openFeatureAnnotationList.forEach(annotation -> { + Map> domainFlags = configuration.getOrDefault(annotation.domain(), new HashMap<>()); + + Arrays.stream(annotation.value()) + .filter(flag -> !domainFlags.containsKey(flag.name())) + .forEach(flag -> { + Flag.FlagBuilder builder = generateFlagBuilder(flag); + domainFlags.put(flag.name(), builder.build()); + }); + addTypedFlags( + annotation, + domainFlags, + nonTypedFlagNamesByDomain.getOrDefault(annotation.domain(), new HashSet<>())); + configuration.put(annotation.domain(), domainFlags); + }); return configuration; } + private static Map> getFlagNamesByDomain(List openFeatureList) { + return openFeatureList.stream() + .map(o -> { + Set flagNames = Arrays.stream(o.value()) + .map(dev.openfeature.contrib.tools.junitopenfeature.Flag::name) + .collect(Collectors.toSet()); + return new AbstractMap.SimpleEntry<>(o.domain(), flagNames); + }) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (t1, t2) -> { + t1.addAll(t2); + return t1; + })); + } + + private static void addTypedFlags(OpenFeature annotation, Map> domainFlags, Set flagNames) { + addBooleanFlags(Arrays.stream(annotation.booleanFlags()), domainFlags, flagNames); + addStringFlags(Arrays.stream(annotation.stringFlags()), domainFlags, flagNames); + addIntegerFlags(Arrays.stream(annotation.integerFlags()), domainFlags, flagNames); + addDoubleFlags(Arrays.stream(annotation.doubleFlags()), domainFlags, flagNames); + } + + private static void addBooleanFlags( + Stream booleanFlags, Map> domainFlags, Set flagNames) { + + booleanFlags.forEach(flag -> addFlag(domainFlags, flagNames, flag.name(), flag.value())); + } + + private static void addStringFlags( + Stream stringFlags, Map> domainFlags, Set flagNames) { + stringFlags.forEach(flag -> addFlag(domainFlags, flagNames, flag.name(), flag.value())); + } + + private static void addIntegerFlags( + Stream integerFlags, Map> domainFlags, Set flagNames) { + integerFlags.forEach(flag -> addFlag(domainFlags, flagNames, flag.name(), flag.value())); + } + + private static void addDoubleFlags( + Stream doubleFlags, Map> domainFlags, Set flagNames) { + doubleFlags.forEach(flag -> addFlag(domainFlags, flagNames, flag.name(), flag.value())); + } + + private static void addFlag( + Map> domainFlags, Set domainFlagNames, String flagName, T value) { + if (domainFlagNames.contains(flagName)) { + throw new IllegalArgumentException("Flag with name " + flagName + " already exists. " + + "There shouldn't be @Flag and @" + value.getClass().getSimpleName() + "Flag with the same name!"); + } + + if (domainFlags.containsKey(flagName)) { + return; + } + Flag.FlagBuilder builder = + Flag.builder().variant(String.valueOf(value), value).defaultVariant(String.valueOf(value)); + domainFlags.put(flagName, builder.build()); + } + private static Map>> handleSimpleConfiguration(ExtensionContext extensionContext) { Map>> configuration = new HashMap<>(); String defaultDomain = PioneerAnnotationUtils.findClosestEnclosingAnnotation( extensionContext, OpenFeatureDefaultDomain.class) .map(OpenFeatureDefaultDomain::value) .orElse(""); - PioneerAnnotationUtils.findAllEnclosingRepeatableAnnotations( - extensionContext, dev.openfeature.contrib.tools.junitopenfeature.Flag.class) - .forEachOrdered(flag -> { - Map> domainFlags = configuration.getOrDefault(defaultDomain, new HashMap<>()); - if (!domainFlags.containsKey(flag.name())) { - Flag.FlagBuilder builder = generateFlagBuilder(flag); - domainFlags.put(flag.name(), builder.build()); - configuration.put(defaultDomain, domainFlags); - } - }); + Map> domainFlags = configuration.getOrDefault(defaultDomain, new HashMap<>()); + List flagList = + PioneerAnnotationUtils.findAllEnclosingRepeatableAnnotations( + extensionContext, dev.openfeature.contrib.tools.junitopenfeature.Flag.class) + .collect(Collectors.toList()); + Set flagNames = flagList.stream() + .map(dev.openfeature.contrib.tools.junitopenfeature.Flag::name) + .collect(Collectors.toSet()); + + flagList.forEach(flag -> { + if (!domainFlags.containsKey(flag.name())) { + Flag.FlagBuilder builder = generateFlagBuilder(flag); + domainFlags.put(flag.name(), builder.build()); + configuration.put(defaultDomain, domainFlags); + } + }); + + Stream booleanFlags = + PioneerAnnotationUtils.findAllEnclosingRepeatableAnnotations(extensionContext, BooleanFlag.class); + addBooleanFlags(booleanFlags, domainFlags, flagNames); + + Stream stringFlags = + PioneerAnnotationUtils.findAllEnclosingRepeatableAnnotations(extensionContext, StringFlag.class); + addStringFlags(stringFlags, domainFlags, flagNames); + + Stream integerFlags = + PioneerAnnotationUtils.findAllEnclosingRepeatableAnnotations(extensionContext, IntegerFlag.class); + addIntegerFlags(integerFlags, domainFlags, flagNames); + + Stream doubleFlags = + PioneerAnnotationUtils.findAllEnclosingRepeatableAnnotations(extensionContext, DoubleFlag.class); + addDoubleFlags(doubleFlags, domainFlags, flagNames); + + if (!domainFlags.isEmpty()) { + configuration.put(defaultDomain, domainFlags); + } return configuration; } diff --git a/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/StringFlag.java b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/StringFlag.java new file mode 100755 index 000000000..f49e7eeeb --- /dev/null +++ b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/StringFlag.java @@ -0,0 +1,28 @@ +package dev.openfeature.contrib.tools.junitopenfeature; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + +/** + * Repeatable annotation that allows you to define String feature flags for the default domain. + * Can be used as a standalone flag configuration but also within {@link OpenFeature}. + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Repeatable(StringFlags.class) +@ExtendWith(OpenFeatureExtension.class) +public @interface StringFlag { + /** + * The key of the FeatureFlag. + */ + String name(); + + /** + * The value of the FeatureFlag. + */ + String value(); +} diff --git a/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/StringFlags.java b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/StringFlags.java new file mode 100755 index 000000000..59a1de9ac --- /dev/null +++ b/tools/junit-openfeature/src/main/java/dev/openfeature/contrib/tools/junitopenfeature/StringFlags.java @@ -0,0 +1,20 @@ +package dev.openfeature.contrib.tools.junitopenfeature; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import org.junit.jupiter.api.extension.ExtendWith; + +/** + * Collection of {@link StringFlag} configurations. + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@ExtendWith(OpenFeatureExtension.class) +public @interface StringFlags { + /** + * Collection of {@link StringFlag} configurations. + */ + StringFlag[] value() default {}; +} 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 e3b77701c..0a105f87c 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 @@ -1,13 +1,21 @@ package dev.openfeature.contrib.tools.junitopenfeature; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.testkit.engine.EventConditions.event; +import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message; import dev.openfeature.sdk.Client; import dev.openfeature.sdk.OpenFeatureAPI; +import org.junit.jupiter.api.Disabled; 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 org.junit.platform.testkit.engine.EngineTestKit; +import org.junit.platform.testkit.engine.Events; class BooleanFlagTest { @@ -20,6 +28,7 @@ class SimpleConfig { @Flag(name = FLAG, value = "true") @Flag(name = FLAG + "2", value = "true") @Flag(name = FLAG + "3", value = "true") + @BooleanFlag(name = FLAG + "4", value = true) class onClass { @Test void multipleFlagsSimple() { @@ -27,6 +36,7 @@ void multipleFlagsSimple() { assertThat(client.getBooleanValue(FLAG, false)).isTrue(); assertThat(client.getBooleanValue(FLAG + "2", false)).isTrue(); assertThat(client.getBooleanValue(FLAG + "3", false)).isTrue(); + assertThat(client.getBooleanValue(FLAG + "4", false)).isTrue(); } } @@ -37,6 +47,13 @@ void existingSimpleFlagIsRetrieved() { assertThat(client.getBooleanValue(FLAG, false)).isTrue(); } + @Test + @BooleanFlag(name = FLAG, value = true) + void existingSimpleTypedFlagIsRetrieved() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getBooleanValue(FLAG, false)).isTrue(); + } + @Test @Flag(name = FLAG, value = "true") @Flag(name = FLAG + "2", value = "true") @@ -48,6 +65,36 @@ void multipleFlagsSimple() { assertThat(client.getBooleanValue(FLAG + "3", false)).isTrue(); } + @Test + @BooleanFlag(name = FLAG, value = true) + @BooleanFlag(name = FLAG + "2", value = true) + void multipleTypedFlagsSimple() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getBooleanValue(FLAG, false)).isTrue(); + assertThat(client.getBooleanValue(FLAG + "2", false)).isTrue(); + } + + @Test + @BooleanFlag(name = FLAG, value = true) + @BooleanFlag(name = FLAG, value = false) + void duplicatedTypedFlagDoesntOverridePrevious() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getBooleanValue(FLAG, false)).isTrue(); + } + + @Test + @Flag(name = FLAG, value = "true") + @Flag(name = FLAG + "2", value = "true") + @Flag(name = FLAG + "3", value = "true") + @BooleanFlag(name = FLAG + "4", value = true) + void multipleDifferentFlagsSimple() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getBooleanValue(FLAG, false)).isTrue(); + assertThat(client.getBooleanValue(FLAG + "2", false)).isTrue(); + assertThat(client.getBooleanValue(FLAG + "3", false)).isTrue(); + assertThat(client.getBooleanValue(FLAG + "4", false)).isTrue(); + } + @ParameterizedTest @ValueSource(ints = {1, 2}) @Flag(name = FLAG, value = "true") @@ -55,6 +102,14 @@ void existingSimpleFlagIsRetrievedOnParameterizedTest() { Client client = OpenFeatureAPI.getInstance().getClient(); assertThat(client.getBooleanValue(FLAG, false)).isTrue(); } + + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @BooleanFlag(name = FLAG, value = true) + void existingSimpleTypedFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getBooleanValue(FLAG, false)).isTrue(); + } } @Nested @@ -64,6 +119,7 @@ class SimpleConfigWithDefault { @Flag(name = FLAG, value = "true") @Flag(name = FLAG + "2", value = "true") @Flag(name = FLAG + "3", value = "true") + @BooleanFlag(name = FLAG + "4", value = true) class onClass { @Test void multipleFlagsSimple() { @@ -71,6 +127,7 @@ void multipleFlagsSimple() { assertThat(client.getBooleanValue(FLAG, false)).isTrue(); assertThat(client.getBooleanValue(FLAG + "2", false)).isTrue(); assertThat(client.getBooleanValue(FLAG + "3", false)).isTrue(); + assertThat(client.getBooleanValue(FLAG + "4", false)).isTrue(); } } @@ -81,6 +138,13 @@ void existingSimpleFlagIsRetrieved() { assertThat(client.getBooleanValue(FLAG, false)).isTrue(); } + @Test + @BooleanFlag(name = FLAG, value = true) + void existingSimpleTypedFlagIsRetrieved() { + Client client = OpenFeatureAPI.getInstance().getClient("testSpecific"); + assertThat(client.getBooleanValue(FLAG, false)).isTrue(); + } + @Test @Flag(name = FLAG, value = "true") @Flag(name = FLAG + "2", value = "true") @@ -92,6 +156,28 @@ void multipleFlagsSimple() { assertThat(client.getBooleanValue(FLAG + "3", false)).isTrue(); } + @Test + @BooleanFlag(name = FLAG, value = true) + @BooleanFlag(name = FLAG + "2", value = true) + void multipleTypedFlagsSimple() { + Client client = OpenFeatureAPI.getInstance().getClient("testSpecific"); + assertThat(client.getBooleanValue(FLAG, false)).isTrue(); + assertThat(client.getBooleanValue(FLAG + "2", false)).isTrue(); + } + + @Test + @Flag(name = FLAG, value = "true") + @Flag(name = FLAG + "2", value = "true") + @Flag(name = FLAG + "3", value = "true") + @BooleanFlag(name = FLAG + "4", value = true) + void multipleDifferentFlagsSimple() { + Client client = OpenFeatureAPI.getInstance().getClient("testSpecific"); + assertThat(client.getBooleanValue(FLAG, false)).isTrue(); + assertThat(client.getBooleanValue(FLAG + "2", false)).isTrue(); + assertThat(client.getBooleanValue(FLAG + "3", false)).isTrue(); + assertThat(client.getBooleanValue(FLAG + "4", false)).isTrue(); + } + @ParameterizedTest @ValueSource(ints = {1, 2}) @Flag(name = FLAG, value = "true") @@ -99,6 +185,14 @@ void existingSimpleFlagIsRetrievedOnParameterizedTest() { Client client = OpenFeatureAPI.getInstance().getClient("testSpecific"); assertThat(client.getBooleanValue(FLAG, false)).isTrue(); } + + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @BooleanFlag(name = FLAG, value = true) + void existingSimpleTypedFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient("testSpecific"); + assertThat(client.getBooleanValue(FLAG, false)).isTrue(); + } } @Nested @@ -110,6 +204,13 @@ void existingFlagIsRetrieved() { assertThat(client.getBooleanValue(FLAG, false)).isTrue(); } + @Test + @OpenFeature(booleanFlags = {@BooleanFlag(name = FLAG + "4", value = true)}) + void existingBooleanFlagIsRetrieved() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getBooleanValue(FLAG + "4", false)).isTrue(); + } + @Test @OpenFeature(@Flag(name = FLAG, value = "truesadf")) void strangeFlagValue() { @@ -124,6 +225,13 @@ void nonExistingFlagIsFallbacked() { assertThat(client.getBooleanValue("nonSetFlag", false)).isFalse(); } + @Test + @OpenFeature(booleanFlags = @BooleanFlag(name = FLAG, value = true)) + void nonExistingTypedFlagIsFallbacked() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getBooleanValue("nonSetFlag", false)).isFalse(); + } + @Test @OpenFeature({ @Flag(name = FLAG, value = "true"), @@ -137,6 +245,18 @@ void multipleFlags() { assertThat(client.getBooleanValue(FLAG + "3", false)).isTrue(); } + @Test + @OpenFeature( + booleanFlags = { + @BooleanFlag(name = FLAG + "4", value = true), + @BooleanFlag(name = FLAG + "5", value = true), + }) + void multipleTypedFlags() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getBooleanValue(FLAG + "4", false)).isTrue(); + assertThat(client.getBooleanValue(FLAG + "5", false)).isTrue(); + } + @ParameterizedTest @ValueSource(ints = {1, 2}) @OpenFeature({@Flag(name = FLAG, value = "true")}) @@ -145,22 +265,43 @@ void existingFlagIsRetrievedOnParameterizedTest() { assertThat(client.getBooleanValue(FLAG, false)).isTrue(); } + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @OpenFeature(booleanFlags = {@BooleanFlag(name = FLAG + "4", value = true)}) + void existingTypedFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getBooleanValue(FLAG + "4", false)).isTrue(); + } + @Nested - @OpenFeature({ - @Flag(name = FLAG, value = "true"), - @Flag(name = FLAG + "2", value = "false"), - }) + @OpenFeature( + value = { + @Flag(name = FLAG, value = "true"), + @Flag(name = FLAG + "2", value = "false"), + }, + booleanFlags = { + @BooleanFlag(name = FLAG + "4", value = true), + @BooleanFlag(name = FLAG + "5", value = false) + }) class MultipleFlags { @Test - @OpenFeature({ - @Flag(name = FLAG + "2", value = "true"), - @Flag(name = FLAG + "3", value = "true"), - }) + @OpenFeature( + value = { + @Flag(name = FLAG + "2", value = "true"), + @Flag(name = FLAG + "3", value = "true"), + }, + booleanFlags = { + @BooleanFlag(name = FLAG + "5", value = true), + @BooleanFlag(name = FLAG + "6", value = true) + }) void multipleFlags() { Client client = OpenFeatureAPI.getInstance().getClient(); assertThat(client.getBooleanValue(FLAG, false)).isTrue(); assertThat(client.getBooleanValue(FLAG + "2", false)).isTrue(); assertThat(client.getBooleanValue(FLAG + "3", false)).isTrue(); + assertThat(client.getBooleanValue(FLAG + "4", false)).isTrue(); + assertThat(client.getBooleanValue(FLAG + "5", false)).isTrue(); + assertThat(client.getBooleanValue(FLAG + "6", false)).isTrue(); } @Test @@ -169,17 +310,68 @@ void multipleFlags() { value = { @Flag(name = FLAG + "2", value = "true"), @Flag(name = FLAG + "3", value = "true"), + }, + booleanFlags = { + @BooleanFlag(name = FLAG + "5", value = true), + @BooleanFlag(name = FLAG + "6", value = true) }) void multipleFlagsOnMultipleDomains() { Client client = OpenFeatureAPI.getInstance().getClient(); assertThat(client.getBooleanValue(FLAG, false)).isTrue(); assertThat(client.getBooleanValue(FLAG + "2", true)).isFalse(); assertThat(client.getBooleanValue(FLAG + "3", false)).isFalse(); + assertThat(client.getBooleanValue(FLAG + "4", false)).isTrue(); + assertThat(client.getBooleanValue(FLAG + "5", false)).isFalse(); Client testSpecific = OpenFeatureAPI.getInstance().getClient("testSpecific"); assertThat(testSpecific.getBooleanValue(FLAG, false)).isFalse(); assertThat(testSpecific.getBooleanValue(FLAG + "2", false)).isTrue(); assertThat(testSpecific.getBooleanValue(FLAG + "3", false)).isTrue(); + assertThat(testSpecific.getBooleanValue(FLAG + "4", false)).isFalse(); + assertThat(testSpecific.getBooleanValue(FLAG + "5", false)).isTrue(); + assertThat(testSpecific.getBooleanValue(FLAG + "6", false)).isTrue(); + } + } + } + + @Nested + class DifferentFlagsWithTheSameNameException { + + @Test + void differentFlagTypesWithTheSameNameThrowsException() { + Events events = EngineTestKit.engine("junit-jupiter") + .configurationParameter("junit.jupiter.conditions.deactivate", "org.junit.*DisabledCondition") + .selectors(selectClass(ConfigWithException.class)) + .execute() + .testEvents() + .failed(); + + events.assertThatEvents() + .haveExactly( + 2, + event(finishedWithFailure( + instanceOf(IllegalArgumentException.class), + message("Flag with name boolean-flag already exists. " + + "There shouldn't be @Flag and @BooleanFlag with the same name!")))); + } + + @Nested + @Disabled + class ConfigWithException { + + @Test + @Flag(name = FLAG, value = "true") + @BooleanFlag(name = FLAG, value = true) + void simpleConfigDuplicateFlags() { + // expect exception in OpenFeatureExtension + } + + @Test + @OpenFeature( + value = {@Flag(name = FLAG, value = "true")}, + booleanFlags = {@BooleanFlag(name = FLAG, value = true)}) + void extendedConfigDuplicateFlags() { + // expect exception in OpenFeatureExtension } } } 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 e2f8db57a..1fc02417c 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 @@ -1,13 +1,21 @@ package dev.openfeature.contrib.tools.junitopenfeature; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.testkit.engine.EventConditions.event; +import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message; import dev.openfeature.sdk.Client; import dev.openfeature.sdk.OpenFeatureAPI; +import org.junit.jupiter.api.Disabled; 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 org.junit.platform.testkit.engine.EngineTestKit; +import org.junit.platform.testkit.engine.Events; class DoubleFlagTest { @@ -29,6 +37,13 @@ void existingSimpleFlagIsRetrieved() { assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); } + @Test + @DoubleFlag(name = FLAG, value = 1.d) + void existingSimpleTypedFlagIsRetrieved() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Test @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Double.class) @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Double.class) @@ -40,10 +55,28 @@ void multipleFlagsSimple() { assertThat(client.getDoubleValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); } + @Test + @DoubleFlag(name = FLAG, value = 1.d) + @DoubleFlag(name = FLAG + "2", value = 1.d) + void multipleTypedFlagsSimple() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getDoubleValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); + } + + @Test + @DoubleFlag(name = FLAG, value = 1.d) + @DoubleFlag(name = FLAG, value = 2.d) + void duplicatedTypedFlagDoesntOverridePrevious() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Nested @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Double.class) @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Double.class) @Flag(name = FLAG + "3", value = FLAG_VALUE_STRING, valueType = Double.class) + @DoubleFlag(name = FLAG + "4", value = 1.d) class onClass { @Test void multipleFlagsSimple() { @@ -51,9 +84,23 @@ void multipleFlagsSimple() { assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getDoubleValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getDoubleValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getDoubleValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); } } + @Test + @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Double.class) + @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Double.class) + @Flag(name = FLAG + "3", value = FLAG_VALUE_STRING, valueType = Double.class) + @DoubleFlag(name = FLAG + "4", value = 1.d) + void multipleDifferentFlagsSimple() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getDoubleValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getDoubleValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getDoubleValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + } + @ParameterizedTest @ValueSource(ints = {1, 2}) @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Double.class) @@ -61,6 +108,14 @@ void existingSimpleFlagIsRetrievedOnParameterizedTest() { Client client = OpenFeatureAPI.getInstance().getClient(); assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); } + + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @DoubleFlag(name = FLAG, value = 1.d) + void existingSimpleTypedFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } } @Nested @@ -73,6 +128,13 @@ void existingSimpleFlagIsRetrieved() { assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); } + @Test + @DoubleFlag(name = FLAG, value = 1.d) + void existingSimpleTypedFlagIsRetrieved() { + Client client = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); + assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Test @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Double.class) @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Double.class) @@ -84,10 +146,20 @@ void multipleFlagsSimple() { assertThat(client.getDoubleValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); } + @Test + @DoubleFlag(name = FLAG, value = 1.d) + @DoubleFlag(name = FLAG + "2", value = 1.d) + void multipleTypedFlagsSimple() { + Client client = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); + assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getDoubleValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Nested @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Double.class) @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Double.class) @Flag(name = FLAG + "3", value = FLAG_VALUE_STRING, valueType = Double.class) + @DoubleFlag(name = FLAG + "4", value = 1.d) class onClass { @Test void multipleFlagsSimple() { @@ -95,9 +167,23 @@ void multipleFlagsSimple() { assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getDoubleValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getDoubleValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getDoubleValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); } } + @Test + @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Double.class) + @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Double.class) + @Flag(name = FLAG + "3", value = FLAG_VALUE_STRING, valueType = Double.class) + @DoubleFlag(name = FLAG + "4", value = 1.d) + void multipleDifferentFlagsSimple() { + Client client = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); + assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getDoubleValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getDoubleValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getDoubleValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + } + @ParameterizedTest @ValueSource(ints = {1, 2}) @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Double.class) @@ -105,6 +191,14 @@ void existingSimpleFlagIsRetrievedOnParameterizedTest() { Client client = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); } + + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @DoubleFlag(name = FLAG, value = 1.d) + void existingSimpleTypedFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); + assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } } @Nested @@ -116,6 +210,13 @@ void existingFlagIsRetrieved() { assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); } + @Test + @OpenFeature(doubleFlags = {@DoubleFlag(name = FLAG + "4", value = 1.d)}) + void existingDoubleFlagIsRetrieved() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getDoubleValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Test @OpenFeature(@Flag(name = FLAG, value = "truesadf")) void strangeFlagValue() { @@ -130,6 +231,13 @@ void nonExistingFlagIsFallbacked() { assertThat(client.getDoubleValue("nonSetFlag", FALLBACK)).isEqualTo(FALLBACK); } + @Test + @OpenFeature(doubleFlags = @DoubleFlag(name = FLAG, value = 1.d)) + void nonExistingTypedFlagIsFallbacked() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getDoubleValue("nonSetFlag", FALLBACK)).isEqualTo(FALLBACK); + } + @Test @OpenFeature({ @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Double.class), @@ -143,6 +251,18 @@ void multipleFlags() { assertThat(client.getDoubleValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); } + @Test + @OpenFeature( + doubleFlags = { + @DoubleFlag(name = FLAG + "4", value = 1.d), + @DoubleFlag(name = FLAG + "5", value = 1.d), + }) + void multipleTypedFlags() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getDoubleValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getDoubleValue(FLAG + "5", FALLBACK)).isEqualTo(FLAG_VALUE); + } + @ParameterizedTest @ValueSource(ints = {1, 2}) @OpenFeature({@Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Double.class)}) @@ -151,22 +271,41 @@ void existingFlagIsRetrievedOnParameterizedTest() { assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); } + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @OpenFeature(doubleFlags = {@DoubleFlag(name = FLAG + "4", value = 1.d)}) + void existingTypedFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getDoubleValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Nested - @OpenFeature({ - @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Double.class), - @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING_ALTERNATIVE, valueType = Double.class), - }) + @OpenFeature( + value = { + @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Double.class), + @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING_ALTERNATIVE, valueType = Double.class), + }, + doubleFlags = {@DoubleFlag(name = FLAG + "4", value = 1.d), @DoubleFlag(name = FLAG + "5", value = 0.0) + }) class MultipleFlags { @Test - @OpenFeature({ - @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Double.class), - @Flag(name = FLAG + "3", value = FLAG_VALUE_STRING, valueType = Double.class), - }) + @OpenFeature( + value = { + @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Double.class), + @Flag(name = FLAG + "3", value = FLAG_VALUE_STRING, valueType = Double.class), + }, + doubleFlags = { + @DoubleFlag(name = FLAG + "5", value = 1.d), + @DoubleFlag(name = FLAG + "6", value = 1.0) + }) void multipleFlags() { Client client = OpenFeatureAPI.getInstance().getClient(); assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getDoubleValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getDoubleValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getDoubleValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getDoubleValue(FLAG + "5", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getDoubleValue(FLAG + "6", FALLBACK)).isEqualTo(FLAG_VALUE); } @Test @@ -175,17 +314,68 @@ void multipleFlags() { value = { @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Double.class), @Flag(name = FLAG + "3", value = FLAG_VALUE_STRING, valueType = Double.class), + }, + doubleFlags = { + @DoubleFlag(name = FLAG + "5", value = 1.d), + @DoubleFlag(name = FLAG + "6", value = 1.0) }) void multipleFlagsOnMultipleDomains() { Client client = OpenFeatureAPI.getInstance().getClient(); assertThat(client.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getDoubleValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE_ALTERNATIVE); assertThat(client.getDoubleValue(FLAG + "3", FALLBACK)).isEqualTo(FALLBACK); + assertThat(client.getDoubleValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getDoubleValue(FLAG + "5", FALLBACK)).isEqualTo(FLAG_VALUE_ALTERNATIVE); Client testSpecific = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); assertThat(testSpecific.getDoubleValue(FLAG, FALLBACK)).isEqualTo(FALLBACK); assertThat(testSpecific.getDoubleValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(testSpecific.getDoubleValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(testSpecific.getDoubleValue(FLAG + "4", FALLBACK)).isEqualTo(FALLBACK); + assertThat(testSpecific.getDoubleValue(FLAG + "5", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(testSpecific.getDoubleValue(FLAG + "6", FALLBACK)).isEqualTo(FLAG_VALUE); + } + } + } + + @Nested + class DifferentFlagsWithTheSameNameException { + + @Test + void differentFlagTypesWithTheSameNameThrowsException() { + Events events = EngineTestKit.engine("junit-jupiter") + .configurationParameter("junit.jupiter.conditions.deactivate", "org.junit.*DisabledCondition") + .selectors(selectClass(ConfigWithException.class)) + .execute() + .testEvents() + .failed(); + + events.assertThatEvents() + .haveExactly( + 2, + event(finishedWithFailure( + instanceOf(IllegalArgumentException.class), + message("Flag with name double-flag already exists. " + + "There shouldn't be @Flag and @DoubleFlag with the same name!")))); + } + + @Nested + @Disabled + class ConfigWithException { + + @Test + @Flag(name = FLAG, value = FLAG_VALUE_STRING) + @DoubleFlag(name = FLAG, value = 1.0) + void simpleConfigDuplicateFlags() { + // expect exception in OpenFeatureExtension + } + + @Test + @OpenFeature( + value = {@Flag(name = FLAG, value = FLAG_VALUE_STRING)}, + doubleFlags = {@DoubleFlag(name = FLAG, value = 1.0)}) + void extendedConfigDuplicateFlags() { + // expect exception in OpenFeatureExtension } } } 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 5db7be9b3..49fb536df 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 @@ -1,13 +1,21 @@ package dev.openfeature.contrib.tools.junitopenfeature; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.testkit.engine.EventConditions.event; +import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message; import dev.openfeature.sdk.Client; import dev.openfeature.sdk.OpenFeatureAPI; +import org.junit.jupiter.api.Disabled; 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 org.junit.platform.testkit.engine.EngineTestKit; +import org.junit.platform.testkit.engine.Events; class IntegerFlagTest { @@ -29,6 +37,13 @@ void existingSimpleFlagIsRetrieved() { assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); } + @Test + @IntegerFlag(name = FLAG, value = 1) + void existingSimpleTypedFlagIsRetrieved() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Test @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Integer.class) @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Integer.class) @@ -40,10 +55,28 @@ void multipleFlagsSimple() { assertThat(client.getIntegerValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); } + @Test + @IntegerFlag(name = FLAG, value = 1) + @IntegerFlag(name = FLAG + "2", value = 1) + void multipleTypedFlagsSimple() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getIntegerValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); + } + + @Test + @IntegerFlag(name = FLAG, value = 1) + @IntegerFlag(name = FLAG, value = 2) + void duplicatedTypedFlagDoesntOverridePrevious() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Nested @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Integer.class) @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Integer.class) @Flag(name = FLAG + "3", value = FLAG_VALUE_STRING, valueType = Integer.class) + @IntegerFlag(name = FLAG + "4", value = 1) class onClass { @Test void multipleFlagsSimple() { @@ -51,9 +84,23 @@ void multipleFlagsSimple() { assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getIntegerValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getIntegerValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getIntegerValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); } } + @Test + @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Integer.class) + @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Integer.class) + @Flag(name = FLAG + "3", value = FLAG_VALUE_STRING, valueType = Integer.class) + @IntegerFlag(name = FLAG + "4", value = 1) + void multipleDifferentFlagsSimple() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getIntegerValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getIntegerValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getIntegerValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + } + @ParameterizedTest @ValueSource(ints = {1, 2}) @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Integer.class) @@ -61,6 +108,14 @@ void existingSimpleFlagIsRetrievedOnParameterizedTest() { Client client = OpenFeatureAPI.getInstance().getClient(); assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); } + + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @IntegerFlag(name = FLAG, value = 1) + void existingSimpleTypedFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } } @Nested @@ -73,6 +128,13 @@ void existingSimpleFlagIsRetrieved() { assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); } + @Test + @IntegerFlag(name = FLAG, value = 1) + void existingSimpleTypedFlagIsRetrieved() { + Client client = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); + assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Test @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Integer.class) @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Integer.class) @@ -84,10 +146,20 @@ void multipleFlagsSimple() { assertThat(client.getIntegerValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); } + @Test + @IntegerFlag(name = FLAG, value = 1) + @IntegerFlag(name = FLAG + "2", value = 1) + void multipleTypedFlagsSimple() { + Client client = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); + assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getIntegerValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Nested @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Integer.class) @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Integer.class) @Flag(name = FLAG + "3", value = FLAG_VALUE_STRING, valueType = Integer.class) + @IntegerFlag(name = FLAG + "4", value = 1) class onClass { @Test void multipleFlagsSimple() { @@ -95,9 +167,23 @@ void multipleFlagsSimple() { assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getIntegerValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getIntegerValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getIntegerValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); } } + @Test + @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Integer.class) + @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Integer.class) + @Flag(name = FLAG + "3", value = FLAG_VALUE_STRING, valueType = Integer.class) + @IntegerFlag(name = FLAG + "4", value = 1) + void multipleDifferentFlagsSimple() { + Client client = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); + assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getIntegerValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getIntegerValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getIntegerValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + } + @ParameterizedTest @ValueSource(ints = {1, 2}) @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Integer.class) @@ -105,6 +191,14 @@ void existingSimpleFlagIsRetrievedOnParameterizedTest() { Client client = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); } + + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @IntegerFlag(name = FLAG, value = 1) + void existingSimpleTypedFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); + assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } } @Nested @@ -116,6 +210,13 @@ void existingFlagIsRetrieved() { assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); } + @Test + @OpenFeature(integerFlags = {@IntegerFlag(name = FLAG + "4", value = 1)}) + void existingIntegerFlagIsRetrieved() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getIntegerValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Test @OpenFeature(@Flag(name = FLAG, value = "truesadf")) void strangeFlagValue() { @@ -131,11 +232,19 @@ void nonExistingFlagIsFallbacked() { } @Test - @OpenFeature({ - @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Integer.class), - @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Integer.class), - @Flag(name = FLAG + "3", value = FLAG_VALUE_STRING, valueType = Integer.class), - }) + @OpenFeature(integerFlags = @IntegerFlag(name = FLAG, value = 1)) + void nonExistingTypedFlagIsFallbacked() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getIntegerValue("nonSetFlag", FALLBACK)).isEqualTo(FALLBACK); + } + + @Test + @OpenFeature( + value = { + @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Integer.class), + @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Integer.class), + @Flag(name = FLAG + "3", value = FLAG_VALUE_STRING, valueType = Integer.class), + }) void multipleFlags() { Client client = OpenFeatureAPI.getInstance().getClient(); assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); @@ -143,6 +252,18 @@ void multipleFlags() { assertThat(client.getIntegerValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); } + @Test + @OpenFeature( + integerFlags = { + @IntegerFlag(name = FLAG + "4", value = 1), + @IntegerFlag(name = FLAG + "5", value = 1), + }) + void multipleTypedFlags() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getIntegerValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getIntegerValue(FLAG + "5", FALLBACK)).isEqualTo(FLAG_VALUE); + } + @ParameterizedTest @ValueSource(ints = {1, 2}) @OpenFeature({@Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Integer.class)}) @@ -151,22 +272,40 @@ void existingSimpleFlagIsRetrievedOnParameterizedTest() { assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); } + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @OpenFeature(integerFlags = {@IntegerFlag(name = FLAG + "4", value = 1)}) + void existingTypedFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getIntegerValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Nested - @OpenFeature({ - @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Integer.class), - @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING_ALTERNATIVE, valueType = Integer.class), - }) + @OpenFeature( + value = { + @Flag(name = FLAG, value = FLAG_VALUE_STRING, valueType = Integer.class), + @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING_ALTERNATIVE, valueType = Integer.class), + }, + integerFlags = {@IntegerFlag(name = FLAG + "4", value = 1), @IntegerFlag(name = FLAG + "5", value = 0)}) class MultipleFlags { @Test - @OpenFeature({ - @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Integer.class), - @Flag(name = FLAG + "3", value = FLAG_VALUE_STRING, valueType = Integer.class), - }) + @OpenFeature( + value = { + @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Integer.class), + @Flag(name = FLAG + "3", value = FLAG_VALUE_STRING, valueType = Integer.class), + }, + integerFlags = { + @IntegerFlag(name = FLAG + "5", value = 1), + @IntegerFlag(name = FLAG + "6", value = 1) + }) void multipleFlags() { Client client = OpenFeatureAPI.getInstance().getClient(); assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getIntegerValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getIntegerValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getIntegerValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getIntegerValue(FLAG + "5", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getIntegerValue(FLAG + "6", FALLBACK)).isEqualTo(FLAG_VALUE); } @Test @@ -175,17 +314,68 @@ void multipleFlags() { value = { @Flag(name = FLAG + "2", value = FLAG_VALUE_STRING, valueType = Integer.class), @Flag(name = FLAG + "3", value = FLAG_VALUE_STRING, valueType = Integer.class), + }, + integerFlags = { + @IntegerFlag(name = FLAG + "5", value = 1), + @IntegerFlag(name = FLAG + "6", value = 1) }) void multipleFlagsOnMultipleDomains() { Client client = OpenFeatureAPI.getInstance().getClient(); assertThat(client.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getIntegerValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE_ALTERNATIVE); assertThat(client.getIntegerValue(FLAG + "3", FALLBACK)).isEqualTo(FALLBACK); + assertThat(client.getIntegerValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getIntegerValue(FLAG + "5", FALLBACK)).isEqualTo(FLAG_VALUE_ALTERNATIVE); Client testSpecific = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); assertThat(testSpecific.getIntegerValue(FLAG, FALLBACK)).isEqualTo(FALLBACK); assertThat(testSpecific.getIntegerValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(testSpecific.getIntegerValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(testSpecific.getIntegerValue(FLAG + "4", FALLBACK)).isEqualTo(FALLBACK); + assertThat(testSpecific.getIntegerValue(FLAG + "5", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(testSpecific.getIntegerValue(FLAG + "6", FALLBACK)).isEqualTo(FLAG_VALUE); + } + } + } + + @Nested + class DifferentFlagsWithTheSameNameException { + + @Test + void differentFlagTypesWithTheSameNameThrowsException() { + Events events = EngineTestKit.engine("junit-jupiter") + .configurationParameter("junit.jupiter.conditions.deactivate", "org.junit.*DisabledCondition") + .selectors(selectClass(ConfigWithException.class)) + .execute() + .testEvents() + .failed(); + + events.assertThatEvents() + .haveExactly( + 2, + event(finishedWithFailure( + instanceOf(IllegalArgumentException.class), + message("Flag with name integer-flag already exists. " + + "There shouldn't be @Flag and @IntegerFlag with the same name!")))); + } + + @Nested + @Disabled + class ConfigWithException { + + @Test + @Flag(name = FLAG, value = FLAG_VALUE_STRING) + @IntegerFlag(name = FLAG, value = 1) + void simpleConfigDuplicateFlags() { + // expect exception in OpenFeatureExtension + } + + @Test + @OpenFeature( + value = {@Flag(name = FLAG, value = FLAG_VALUE_STRING)}, + integerFlags = {@IntegerFlag(name = FLAG, value = 1)}) + void extendedConfigDuplicateFlags() { + // expect exception in OpenFeatureExtension } } } 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 b7ce8e203..db5bea070 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 @@ -1,13 +1,21 @@ package dev.openfeature.contrib.tools.junitopenfeature; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass; +import static org.junit.platform.testkit.engine.EventConditions.event; +import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.instanceOf; +import static org.junit.platform.testkit.engine.TestExecutionResultConditions.message; import dev.openfeature.sdk.Client; import dev.openfeature.sdk.OpenFeatureAPI; +import org.junit.jupiter.api.Disabled; 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 org.junit.platform.testkit.engine.EngineTestKit; +import org.junit.platform.testkit.engine.Events; class StringFlagTest { @@ -24,6 +32,7 @@ class SimpleConfig { @Flag(name = FLAG, value = FLAG_VALUE, valueType = String.class) @Flag(name = FLAG + "2", value = FLAG_VALUE, valueType = String.class) @Flag(name = FLAG + "3", value = FLAG_VALUE, valueType = String.class) + @StringFlag(name = FLAG + "4", value = FLAG_VALUE) class onClass { @Test void multipleFlagsSimple() { @@ -31,6 +40,7 @@ void multipleFlagsSimple() { assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getStringValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getStringValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getStringValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); } } @@ -41,6 +51,13 @@ void existingSimpleFlagIsRetrieved() { assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); } + @Test + @StringFlag(name = FLAG, value = FLAG_VALUE) + void existingSimpleTypedFlagIsRetrieved() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Test @Flag(name = FLAG, value = FLAG_VALUE, valueType = String.class) @Flag(name = FLAG + "2", value = FLAG_VALUE, valueType = String.class) @@ -52,6 +69,36 @@ void multipleFlagsSimple() { assertThat(client.getStringValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); } + @Test + @StringFlag(name = FLAG, value = FLAG_VALUE) + @StringFlag(name = FLAG + "2", value = FLAG_VALUE) + void multipleTypedFlagsSimple() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getStringValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); + } + + @Test + @StringFlag(name = FLAG, value = FLAG_VALUE) + @StringFlag(name = FLAG, value = FLAG_VALUE_ALTERNATIVE) + void duplicatedTypedFlagDoesntOverridePrevious() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } + + @Test + @Flag(name = FLAG, value = FLAG_VALUE, valueType = String.class) + @Flag(name = FLAG + "2", value = FLAG_VALUE, valueType = String.class) + @Flag(name = FLAG + "3", value = FLAG_VALUE, valueType = String.class) + @StringFlag(name = FLAG + "4", value = FLAG_VALUE) + void multipleDifferentFlagsSimple() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getStringValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getStringValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getStringValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + } + @ParameterizedTest @ValueSource(ints = {1, 2}) @Flag(name = FLAG, value = FLAG_VALUE, valueType = String.class) @@ -59,6 +106,14 @@ void existingSimpleFlagIsRetrievedOnParameterizedTest() { Client client = OpenFeatureAPI.getInstance().getClient(); assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); } + + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @StringFlag(name = FLAG, value = FLAG_VALUE) + void existingSimpleTypedFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } } @Nested @@ -68,6 +123,7 @@ class SimpleConfigWithDefault { @Flag(name = FLAG, value = FLAG_VALUE, valueType = String.class) @Flag(name = FLAG + "2", value = FLAG_VALUE, valueType = String.class) @Flag(name = FLAG + "3", value = FLAG_VALUE, valueType = String.class) + @StringFlag(name = FLAG + "4", value = FLAG_VALUE) class onClass { @Test void multipleFlagsSimple() { @@ -75,6 +131,7 @@ void multipleFlagsSimple() { assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getStringValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getStringValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getStringValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); } } @@ -85,6 +142,13 @@ void existingSimpleFlagIsRetrieved() { assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); } + @Test + @StringFlag(name = FLAG, value = FLAG_VALUE) + void existingSimpleTypedFlagIsRetrieved() { + Client client = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); + assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Test @Flag(name = FLAG, value = FLAG_VALUE, valueType = String.class) @Flag(name = FLAG + "2", value = FLAG_VALUE, valueType = String.class) @@ -96,6 +160,28 @@ void multipleFlagsSimple() { assertThat(client.getStringValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); } + @Test + @StringFlag(name = FLAG, value = FLAG_VALUE) + @StringFlag(name = FLAG + "2", value = FLAG_VALUE) + void multipleTypedFlagsSimple() { + Client client = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); + assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getStringValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); + } + + @Test + @Flag(name = FLAG, value = FLAG_VALUE, valueType = String.class) + @Flag(name = FLAG + "2", value = FLAG_VALUE, valueType = String.class) + @Flag(name = FLAG + "3", value = FLAG_VALUE, valueType = String.class) + @StringFlag(name = FLAG + "4", value = FLAG_VALUE) + void multipleDifferentFlagsSimple() { + Client client = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); + assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getStringValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getStringValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getStringValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + } + @ParameterizedTest @ValueSource(ints = {1, 2}) @Flag(name = FLAG, value = FLAG_VALUE, valueType = String.class) @@ -103,6 +189,14 @@ void existingSimpleFlagIsRetrievedOnParameterizedTest() { Client client = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); } + + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @StringFlag(name = FLAG, value = FLAG_VALUE) + void existingSimpleTypedFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); + assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); + } } @Nested @@ -114,6 +208,13 @@ void existingFlagIsRetrieved() { assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); } + @Test + @OpenFeature(stringFlags = {@StringFlag(name = FLAG + "4", value = FLAG_VALUE)}) + void existingStringFlagIsRetrieved() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getStringValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Test @OpenFeature(@Flag(name = FLAG, value = "truesadf")) void strangeFlagValue() { @@ -128,6 +229,13 @@ void nonExistingFlagIsFallbacked() { assertThat(client.getStringValue("nonSetFlag", FALLBACK)).isEqualTo(FALLBACK); } + @Test + @OpenFeature(stringFlags = @StringFlag(name = FLAG, value = FLAG_VALUE)) + void nonExistingTypedFlagIsFallbacked() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getStringValue("nonSetFlag", FALLBACK)).isEqualTo(FALLBACK); + } + @Test @OpenFeature({ @Flag(name = FLAG, value = FLAG_VALUE, valueType = String.class), @@ -141,6 +249,18 @@ void multipleFlags() { assertThat(client.getStringValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); } + @Test + @OpenFeature( + stringFlags = { + @StringFlag(name = FLAG + "4", value = FLAG_VALUE), + @StringFlag(name = FLAG + "5", value = FLAG_VALUE), + }) + void multipleTypedFlags() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getStringValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getStringValue(FLAG + "5", FALLBACK)).isEqualTo(FLAG_VALUE); + } + @ParameterizedTest @ValueSource(ints = {1, 2}) @OpenFeature({@Flag(name = FLAG, value = FLAG_VALUE, valueType = String.class)}) @@ -149,22 +269,43 @@ void existingSimpleFlagIsRetrievedOnParameterizedTest() { assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); } + @ParameterizedTest + @ValueSource(ints = {1, 2}) + @OpenFeature(stringFlags = {@StringFlag(name = FLAG + "4", value = FLAG_VALUE)}) + void existingTypedFlagIsRetrievedOnParameterizedTest() { + Client client = OpenFeatureAPI.getInstance().getClient(); + assertThat(client.getStringValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + } + @Nested - @OpenFeature({ - @Flag(name = FLAG, value = FLAG_VALUE, valueType = String.class), - @Flag(name = FLAG + "2", value = FLAG_VALUE_ALTERNATIVE, valueType = String.class), - }) + @OpenFeature( + value = { + @Flag(name = FLAG, value = FLAG_VALUE, valueType = String.class), + @Flag(name = FLAG + "2", value = FLAG_VALUE_ALTERNATIVE, valueType = String.class), + }, + stringFlags = { + @StringFlag(name = FLAG + "4", value = FLAG_VALUE), + @StringFlag(name = FLAG + "5", value = FLAG_VALUE_ALTERNATIVE) + }) class MultipleFlags { @Test - @OpenFeature({ - @Flag(name = FLAG + "2", value = FLAG_VALUE, valueType = String.class), - @Flag(name = FLAG + "3", value = FLAG_VALUE, valueType = String.class), - }) + @OpenFeature( + value = { + @Flag(name = FLAG + "2", value = FLAG_VALUE, valueType = String.class), + @Flag(name = FLAG + "3", value = FLAG_VALUE, valueType = String.class), + }, + stringFlags = { + @StringFlag(name = FLAG + "5", value = FLAG_VALUE), + @StringFlag(name = FLAG + "6", value = FLAG_VALUE) + }) void multipleFlags() { Client client = OpenFeatureAPI.getInstance().getClient(); assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getStringValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getStringValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getStringValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getStringValue(FLAG + "5", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getStringValue(FLAG + "6", FALLBACK)).isEqualTo(FLAG_VALUE); } @Test @@ -173,17 +314,68 @@ void multipleFlags() { value = { @Flag(name = FLAG + "2", value = FLAG_VALUE, valueType = String.class), @Flag(name = FLAG + "3", value = FLAG_VALUE, valueType = String.class), + }, + stringFlags = { + @StringFlag(name = FLAG + "5", value = FLAG_VALUE), + @StringFlag(name = FLAG + "6", value = FLAG_VALUE) }) void multipleFlagsOnMultipleDomains() { Client client = OpenFeatureAPI.getInstance().getClient(); assertThat(client.getStringValue(FLAG, FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(client.getStringValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE_ALTERNATIVE); assertThat(client.getStringValue(FLAG + "3", FALLBACK)).isEqualTo(FALLBACK); + assertThat(client.getStringValue(FLAG + "4", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(client.getStringValue(FLAG + "5", FALLBACK)).isEqualTo(FLAG_VALUE_ALTERNATIVE); Client testSpecific = OpenFeatureAPI.getInstance().getClient(SPECIFIC_DOMAIN); assertThat(testSpecific.getStringValue(FLAG, FALLBACK)).isEqualTo(FALLBACK); assertThat(testSpecific.getStringValue(FLAG + "2", FALLBACK)).isEqualTo(FLAG_VALUE); assertThat(testSpecific.getStringValue(FLAG + "3", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(testSpecific.getStringValue(FLAG + "4", FALLBACK)).isEqualTo(FALLBACK); + assertThat(testSpecific.getStringValue(FLAG + "5", FALLBACK)).isEqualTo(FLAG_VALUE); + assertThat(testSpecific.getStringValue(FLAG + "6", FALLBACK)).isEqualTo(FLAG_VALUE); + } + } + } + + @Nested + class DifferentFlagsWithTheSameNameException { + + @Test + void differentFlagTypesWithTheSameNameThrowsException() { + Events events = EngineTestKit.engine("junit-jupiter") + .configurationParameter("junit.jupiter.conditions.deactivate", "org.junit.*DisabledCondition") + .selectors(selectClass(ConfigWithException.class)) + .execute() + .testEvents() + .failed(); + + events.assertThatEvents() + .haveExactly( + 2, + event(finishedWithFailure( + instanceOf(IllegalArgumentException.class), + message("Flag with name string-flag already exists. " + + "There shouldn't be @Flag and @StringFlag with the same name!")))); + } + + @Nested + @Disabled + class ConfigWithException { + + @Test + @Flag(name = FLAG, value = FLAG_VALUE) + @StringFlag(name = FLAG, value = FLAG_VALUE) + void simpleConfigDuplicateFlags() { + // expect exception in OpenFeatureExtension + } + + @Test + @OpenFeature( + value = {@Flag(name = FLAG, value = FLAG_VALUE)}, + stringFlags = {@StringFlag(name = FLAG, value = FLAG_VALUE)}) + void extendedConfigDuplicateFlags() { + // expect exception in OpenFeatureExtension } } }