From 8f4e225af4597ee4f3c0a7fc7241c17fe19bebe1 Mon Sep 17 00:00:00 2001 From: Leo Romanovsky Date: Wed, 25 Mar 2026 20:53:41 -0400 Subject: [PATCH 1/4] fix(03-01): compute correct reason in DDEvaluator instead of hardcoding TARGETING_MATCH - Add Split parameter to resolveVariant for three-way reason computation - Return STATIC for flags with no rules and no shards (simple flags) - Return SPLIT for flags with no rules but with shards (shard-based flags) - Return TARGETING_MATCH for flags with rules (rule-based flags) - Update 9 test assertions: 7 to STATIC, 2 to SPLIT --- .../trace/api/openfeature/DDEvaluator.java | 12 ++++++++--- .../api/openfeature/DDEvaluatorTest.java | 20 ++++++++++--------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/DDEvaluator.java b/products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/DDEvaluator.java index 8b04534b7d1..ac080c71d1b 100644 --- a/products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/DDEvaluator.java +++ b/products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/DDEvaluator.java @@ -125,7 +125,7 @@ public ProviderEvaluation evaluate( for (final Split split : allocation.splits) { if (isEmpty(split.shards)) { return resolveVariant( - target, key, defaultValue, flag, split.variationKey, allocation, context); + target, key, defaultValue, flag, split.variationKey, allocation, split, context); } else { // To match a split, subject must match ALL underlying shards boolean allShardsMatch = true; @@ -137,7 +137,7 @@ public ProviderEvaluation evaluate( } if (allShardsMatch) { return resolveVariant( - target, key, defaultValue, flag, split.variationKey, allocation, context); + target, key, defaultValue, flag, split.variationKey, allocation, split, context); } } } @@ -333,6 +333,7 @@ private static ProviderEvaluation resolveVariant( final Flag flag, final String variationKey, final Allocation allocation, + final Split split, final EvaluationContext context) { final Variant variant = flag.variations.get(variationKey); if (variant == null) { @@ -352,7 +353,12 @@ private static ProviderEvaluation resolveVariant( final ProviderEvaluation result = ProviderEvaluation.builder() .value(mapValue(target, variant.value)) - .reason(Reason.TARGETING_MATCH.name()) + .reason( + !isEmpty(allocation.rules) + ? Reason.TARGETING_MATCH.name() + : !isEmpty(split.shards) + ? Reason.SPLIT.name() + : Reason.STATIC.name()) .variant(variant.key) .flagMetadata(metadataBuilder.build()) .build(); diff --git a/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorTest.java b/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorTest.java index 4b723fac7fb..c28b485c92c 100644 --- a/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorTest.java +++ b/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorTest.java @@ -5,6 +5,8 @@ import static dev.openfeature.sdk.Reason.DEFAULT; import static dev.openfeature.sdk.Reason.DISABLED; import static dev.openfeature.sdk.Reason.ERROR; +import static dev.openfeature.sdk.Reason.SPLIT; +import static dev.openfeature.sdk.Reason.STATIC; import static dev.openfeature.sdk.Reason.TARGETING_MATCH; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; @@ -217,7 +219,7 @@ private static List> evaluateTestCases() { new TestCase<>("default") .flag("simple-string") .targetingKey("") - .result(new Result<>("test-value").reason(TARGETING_MATCH.name()).variant("on")), + .result(new Result<>("test-value").reason(STATIC.name()).variant("on")), new TestCase<>("default") .flag("non-existent-flag") .targetingKey("user-123") @@ -229,15 +231,15 @@ private static List> evaluateTestCases() { new TestCase<>("default") .flag("simple-string") .targetingKey("user-123") - .result(new Result<>("test-value").reason(TARGETING_MATCH.name()).variant("on")), + .result(new Result<>("test-value").reason(STATIC.name()).variant("on")), new TestCase<>(false) .flag("boolean-flag") .targetingKey("user-123") - .result(new Result<>(true).reason(TARGETING_MATCH.name()).variant("enabled")), + .result(new Result<>(true).reason(STATIC.name()).variant("enabled")), new TestCase<>(0) .flag("integer-flag") .targetingKey("user-123") - .result(new Result<>(42).reason(TARGETING_MATCH.name()).variant("forty-two")), + .result(new Result<>(42).reason(STATIC.name()).variant("forty-two")), new TestCase<>("default") .flag("rule-based-flag") .targetingKey("user-premium") @@ -247,7 +249,7 @@ private static List> evaluateTestCases() { .flag("rule-based-flag") .targetingKey("user-basic") .context("email", "john@gmail.com") - .result(new Result<>("basic").reason(TARGETING_MATCH.name()).variant("basic")), + .result(new Result<>("basic").reason(STATIC.name()).variant("basic")), new TestCase<>("default") .flag("numeric-rule-flag") .targetingKey("user-vip") @@ -273,11 +275,11 @@ private static List> evaluateTestCases() { .result( new Result<>("default") // Result depends on shard calculation - either match or default - .reason(TARGETING_MATCH.name(), DEFAULT.name())), + .reason(SPLIT.name(), DEFAULT.name())), new TestCase<>(0) .flag("string-number-flag") .targetingKey("user-123") - .result(new Result<>(123).reason(TARGETING_MATCH.name()).variant("string-num")), + .result(new Result<>(123).reason(STATIC.name()).variant("string-num")), new TestCase<>("default") .flag("broken-flag") .targetingKey("user-123") @@ -328,7 +330,7 @@ private static List> evaluateTestCases() { .targetingKey("user-123") .result( new Result<>("tracked-value") - .reason(TARGETING_MATCH.name()) + .reason(STATIC.name()) .variant("tracked") .flagMetadata("allocationKey", "exposure-alloc") .flagMetadata("doLog", true)), @@ -402,7 +404,7 @@ private static List> evaluateTestCases() { .flag("shard-matching-flag") .targetingKey("specific-key-that-matches-shard") .result( - new Result<>("shard-matched").reason(TARGETING_MATCH.name()).variant("matched")), + new Result<>("shard-matched").reason(SPLIT.name()).variant("matched")), new TestCase<>("default") .flag("future-allocation-flag") .targetingKey("user-123") From 6bae689e25eeea0d0ce4a3848be0135a2324f751 Mon Sep 17 00:00:00 2001 From: Leo Romanovsky Date: Wed, 25 Mar 2026 23:05:44 -0400 Subject: [PATCH 2/4] style: apply spotless formatting --- .../datadog/trace/api/openfeature/DDEvaluator.java | 13 +++++++++---- .../trace/api/openfeature/DDEvaluatorTest.java | 3 +-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/DDEvaluator.java b/products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/DDEvaluator.java index ac080c71d1b..a0d96b2c3de 100644 --- a/products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/DDEvaluator.java +++ b/products/feature-flagging/feature-flagging-api/src/main/java/datadog/trace/api/openfeature/DDEvaluator.java @@ -137,7 +137,14 @@ public ProviderEvaluation evaluate( } if (allShardsMatch) { return resolveVariant( - target, key, defaultValue, flag, split.variationKey, allocation, split, context); + target, + key, + defaultValue, + flag, + split.variationKey, + allocation, + split, + context); } } } @@ -356,9 +363,7 @@ private static ProviderEvaluation resolveVariant( .reason( !isEmpty(allocation.rules) ? Reason.TARGETING_MATCH.name() - : !isEmpty(split.shards) - ? Reason.SPLIT.name() - : Reason.STATIC.name()) + : !isEmpty(split.shards) ? Reason.SPLIT.name() : Reason.STATIC.name()) .variant(variant.key) .flagMetadata(metadataBuilder.build()) .build(); diff --git a/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorTest.java b/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorTest.java index c28b485c92c..c6af3ddeb60 100644 --- a/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorTest.java +++ b/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorTest.java @@ -403,8 +403,7 @@ private static List> evaluateTestCases() { new TestCase<>("default") .flag("shard-matching-flag") .targetingKey("specific-key-that-matches-shard") - .result( - new Result<>("shard-matched").reason(SPLIT.name()).variant("matched")), + .result(new Result<>("shard-matched").reason(SPLIT.name()).variant("matched")), new TestCase<>("default") .flag("future-allocation-flag") .targetingKey("user-123") From 60dcb5af98c382a95c7c16545c3236ac9c4c90db Mon Sep 17 00:00:00 2001 From: Leo Romanovsky Date: Wed, 25 Mar 2026 23:25:50 -0400 Subject: [PATCH 3/4] test(06-01): copy Go canonical UFC fixtures into Java test resources - Add ufc-config.json (canonical server configuration) - Add 24 evaluation-case JSON files from dd-trace-go - Files are byte-identical copies of Go reference fixtures --- .../test-case-boolean-false-assignment.json | 41 + .../test-case-boolean-one-of-matches.json | 208 + .../test-case-comparator-operator-flag.json | 69 + .../test-case-disabled-flag.json | 43 + .../test-case-empty-flag.json | 43 + .../test-case-empty-string-variation.json | 41 + .../test-case-falsy-value-assignments.json | 41 + .../test-case-flag-with-empty-string.json | 26 + .../test-case-integer-flag.json | 267 ++ .../test-case-kill-switch-flag.json | 314 ++ .../test-case-microsecond-date-flag.json | 39 + .../test-case-new-user-onboarding-flag.json | 344 ++ .../test-case-no-allocations-flag.json | 55 + .../test-case-null-operator-flag.json | 69 + .../test-case-numeric-flag.json | 43 + .../test-case-numeric-one-of.json | 93 + .../test-case-of-7-empty-targeting-key.json | 13 + .../test-case-regex-flag.json | 57 + .../test-case-start-and-end-date-flag.json | 43 + .../test-flag-that-does-not-exist.json | 43 + .../test-json-config-flag.json | 76 + .../test-no-allocations-flag.json | 55 + .../test-special-characters.json | 58 + .../test-string-with-special-characters.json | 860 +++++ .../src/test/resources/ufc-config.json | 3353 +++++++++++++++++ 25 files changed, 6294 insertions(+) create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-boolean-false-assignment.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-boolean-one-of-matches.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-comparator-operator-flag.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-disabled-flag.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-empty-flag.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-empty-string-variation.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-falsy-value-assignments.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-flag-with-empty-string.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-integer-flag.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-kill-switch-flag.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-microsecond-date-flag.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-new-user-onboarding-flag.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-no-allocations-flag.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-null-operator-flag.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-numeric-flag.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-numeric-one-of.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-of-7-empty-targeting-key.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-regex-flag.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-start-and-end-date-flag.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-flag-that-does-not-exist.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-json-config-flag.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-no-allocations-flag.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-special-characters.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-string-with-special-characters.json create mode 100644 products/feature-flagging/feature-flagging-api/src/test/resources/ufc-config.json diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-boolean-false-assignment.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-boolean-false-assignment.json new file mode 100644 index 00000000000..ab718f5bee1 --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-boolean-false-assignment.json @@ -0,0 +1,41 @@ +[ + { + "attributes": { + "should_disable_feature": true + }, + "defaultValue": true, + "flag": "boolean-false-assignment", + "result": { + "reason": "TARGETING_MATCH", + "value": false + }, + "targetingKey": "alice", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "should_disable_feature": false + }, + "defaultValue": true, + "flag": "boolean-false-assignment", + "result": { + "reason": "TARGETING_MATCH", + "value": true + }, + "targetingKey": "bob", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "unknown_attribute": "value" + }, + "defaultValue": true, + "flag": "boolean-false-assignment", + "result": { + "reason": "DEFAULT", + "value": true + }, + "targetingKey": "charlie", + "variationType": "BOOLEAN" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-boolean-one-of-matches.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-boolean-one-of-matches.json new file mode 100644 index 00000000000..392ec97ec0f --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-boolean-one-of-matches.json @@ -0,0 +1,208 @@ +[ + { + "attributes": { + "one_of_flag": true + }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", + "result": { + "reason": "TARGETING_MATCH", + "value": 1 + }, + "targetingKey": "alice", + "variationType": "INTEGER" + }, + { + "attributes": { + "one_of_flag": false + }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", + "result": { + "reason": "DEFAULT", + "value": 0 + }, + "targetingKey": "bob", + "variationType": "INTEGER" + }, + { + "attributes": { + "one_of_flag": "True" + }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", + "result": { + "reason": "DEFAULT", + "value": 0 + }, + "targetingKey": "charlie", + "variationType": "INTEGER" + }, + { + "attributes": { + "matches_flag": true + }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", + "result": { + "reason": "TARGETING_MATCH", + "value": 2 + }, + "targetingKey": "derek", + "variationType": "INTEGER" + }, + { + "attributes": { + "matches_flag": false + }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", + "result": { + "reason": "DEFAULT", + "value": 0 + }, + "targetingKey": "erica", + "variationType": "INTEGER" + }, + { + "attributes": { + "not_matches_flag": false + }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", + "result": { + "reason": "DEFAULT", + "value": 0 + }, + "targetingKey": "frank", + "variationType": "INTEGER" + }, + { + "attributes": { + "not_matches_flag": true + }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", + "result": { + "reason": "TARGETING_MATCH", + "value": 4 + }, + "targetingKey": "george", + "variationType": "INTEGER" + }, + { + "attributes": { + "not_matches_flag": "False" + }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", + "result": { + "reason": "TARGETING_MATCH", + "value": 4 + }, + "targetingKey": "haley", + "variationType": "INTEGER" + }, + { + "attributes": { + "not_one_of_flag": true + }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", + "result": { + "reason": "TARGETING_MATCH", + "value": 3 + }, + "targetingKey": "ivy", + "variationType": "INTEGER" + }, + { + "attributes": { + "not_one_of_flag": false + }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", + "result": { + "reason": "DEFAULT", + "value": 0 + }, + "targetingKey": "julia", + "variationType": "INTEGER" + }, + { + "attributes": { + "not_one_of_flag": "False" + }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", + "result": { + "reason": "TARGETING_MATCH", + "value": 3 + }, + "targetingKey": "kim", + "variationType": "INTEGER" + }, + { + "attributes": { + "not_one_of_flag": "true" + }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", + "result": { + "reason": "TARGETING_MATCH", + "value": 3 + }, + "targetingKey": "lucas", + "variationType": "INTEGER" + }, + { + "attributes": { + "not_one_of_flag": "false" + }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", + "result": { + "reason": "DEFAULT", + "value": 0 + }, + "targetingKey": "mike", + "variationType": "INTEGER" + }, + { + "attributes": { + "null_flag": "null" + }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", + "result": { + "reason": "TARGETING_MATCH", + "value": 5 + }, + "targetingKey": "nicole", + "variationType": "INTEGER" + }, + { + "attributes": { + "null_flag": null + }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", + "result": { + "reason": "DEFAULT", + "value": 0 + }, + "targetingKey": "owen", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "boolean-one-of-matches", + "result": { + "reason": "DEFAULT", + "value": 0 + }, + "targetingKey": "pete", + "variationType": "INTEGER" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-comparator-operator-flag.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-comparator-operator-flag.json new file mode 100644 index 00000000000..e4daa2de7c2 --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-comparator-operator-flag.json @@ -0,0 +1,69 @@ +[ + { + "attributes": { + "country": "US", + "size": 5 + }, + "defaultValue": "unknown", + "flag": "comparator-operator-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "small" + }, + "targetingKey": "alice", + "variationType": "STRING" + }, + { + "attributes": { + "country": "Canada", + "size": 10 + }, + "defaultValue": "unknown", + "flag": "comparator-operator-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "medium" + }, + "targetingKey": "bob", + "variationType": "STRING" + }, + { + "attributes": { + "size": 25 + }, + "defaultValue": "unknown", + "flag": "comparator-operator-test", + "result": { + "reason": "DEFAULT", + "value": "unknown" + }, + "targetingKey": "charlie", + "variationType": "STRING" + }, + { + "attributes": { + "size": 26 + }, + "defaultValue": "unknown", + "flag": "comparator-operator-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "large" + }, + "targetingKey": "david", + "variationType": "STRING" + }, + { + "attributes": { + "country": "UK" + }, + "defaultValue": "unknown", + "flag": "comparator-operator-test", + "result": { + "reason": "DEFAULT", + "value": "unknown" + }, + "targetingKey": "elize", + "variationType": "STRING" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-disabled-flag.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-disabled-flag.json new file mode 100644 index 00000000000..208e5c96943 --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-disabled-flag.json @@ -0,0 +1,43 @@ +[ + { + "attributes": { + "country": "US", + "email": "alice@mycompany.com" + }, + "defaultValue": 0, + "flag": "disabled_flag", + "result": { + "reason": "DISABLED", + "value": 0 + }, + "targetingKey": "alice", + "variationType": "INTEGER" + }, + { + "attributes": { + "country": "Canada", + "email": "bob@example.com" + }, + "defaultValue": 0, + "flag": "disabled_flag", + "result": { + "reason": "DISABLED", + "value": 0 + }, + "targetingKey": "bob", + "variationType": "INTEGER" + }, + { + "attributes": { + "age": 50 + }, + "defaultValue": 0, + "flag": "disabled_flag", + "result": { + "reason": "DISABLED", + "value": 0 + }, + "targetingKey": "charlie", + "variationType": "INTEGER" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-empty-flag.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-empty-flag.json new file mode 100644 index 00000000000..18ee5381fdc --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-empty-flag.json @@ -0,0 +1,43 @@ +[ + { + "attributes": { + "country": "US", + "email": "alice@mycompany.com" + }, + "defaultValue": "default_value", + "flag": "empty_flag", + "result": { + "reason": "DEFAULT", + "value": "default_value" + }, + "targetingKey": "alice", + "variationType": "STRING" + }, + { + "attributes": { + "country": "Canada", + "email": "bob@example.com" + }, + "defaultValue": "default_value", + "flag": "empty_flag", + "result": { + "reason": "DEFAULT", + "value": "default_value" + }, + "targetingKey": "bob", + "variationType": "STRING" + }, + { + "attributes": { + "age": 50 + }, + "defaultValue": "default_value", + "flag": "empty_flag", + "result": { + "reason": "DEFAULT", + "value": "default_value" + }, + "targetingKey": "charlie", + "variationType": "STRING" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-empty-string-variation.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-empty-string-variation.json new file mode 100644 index 00000000000..f1fa3994af2 --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-empty-string-variation.json @@ -0,0 +1,41 @@ +[ + { + "attributes": { + "content_type": "minimal" + }, + "defaultValue": "default_value", + "flag": "empty-string-variation", + "result": { + "reason": "TARGETING_MATCH", + "value": "" + }, + "targetingKey": "empty_user", + "variationType": "STRING" + }, + { + "attributes": { + "content_type": "full" + }, + "defaultValue": "default_value", + "flag": "empty-string-variation", + "result": { + "reason": "TARGETING_MATCH", + "value": "detailed_content" + }, + "targetingKey": "full_user", + "variationType": "STRING" + }, + { + "attributes": { + "content_type": "unknown" + }, + "defaultValue": "default_value", + "flag": "empty-string-variation", + "result": { + "reason": "DEFAULT", + "value": "default_value" + }, + "targetingKey": "default_user", + "variationType": "STRING" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-falsy-value-assignments.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-falsy-value-assignments.json new file mode 100644 index 00000000000..6a8cee51bcc --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-falsy-value-assignments.json @@ -0,0 +1,41 @@ +[ + { + "attributes": { + "plan_tier": "free" + }, + "defaultValue": 999, + "flag": "falsy-value-assignments", + "result": { + "reason": "TARGETING_MATCH", + "value": 0 + }, + "targetingKey": "zero_user", + "variationType": "INTEGER" + }, + { + "attributes": { + "plan_tier": "premium" + }, + "defaultValue": 999, + "flag": "falsy-value-assignments", + "result": { + "reason": "TARGETING_MATCH", + "value": 100 + }, + "targetingKey": "premium_user", + "variationType": "INTEGER" + }, + { + "attributes": { + "plan_tier": "trial" + }, + "defaultValue": 999, + "flag": "falsy-value-assignments", + "result": { + "reason": "DEFAULT", + "value": 999 + }, + "targetingKey": "unknown_user", + "variationType": "INTEGER" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-flag-with-empty-string.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-flag-with-empty-string.json new file mode 100644 index 00000000000..6a5d9cd62fd --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-flag-with-empty-string.json @@ -0,0 +1,26 @@ +[ + { + "attributes": { + "country": "US" + }, + "defaultValue": "default", + "flag": "empty_string_flag", + "result": { + "reason": "TARGETING_MATCH", + "value": "" + }, + "targetingKey": "alice", + "variationType": "STRING" + }, + { + "attributes": {}, + "defaultValue": "default", + "flag": "empty_string_flag", + "result": { + "reason": "SPLIT", + "value": "non_empty" + }, + "targetingKey": "bob", + "variationType": "STRING" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-integer-flag.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-integer-flag.json new file mode 100644 index 00000000000..8ff11aec1fc --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-integer-flag.json @@ -0,0 +1,267 @@ +[ + { + "attributes": { + "country": "US", + "email": "alice@mycompany.com" + }, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "TARGETING_MATCH", + "value": 3 + }, + "targetingKey": "alice", + "variationType": "INTEGER" + }, + { + "attributes": { + "country": "Canada", + "email": "bob@example.com" + }, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "TARGETING_MATCH", + "value": 3 + }, + "targetingKey": "bob", + "variationType": "INTEGER" + }, + { + "attributes": { + "age": 50 + }, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 2 + }, + "targetingKey": "charlie", + "variationType": "INTEGER" + }, + { + "attributes": { + "age": 25, + "country": "Mexico", + "email": "test@test.com" + }, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "TARGETING_MATCH", + "value": 3 + }, + "targetingKey": "debra", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 2 + }, + "targetingKey": "1", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 2 + }, + "targetingKey": "2", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 2 + }, + "targetingKey": "3", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 2 + }, + "targetingKey": "4", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 1 + }, + "targetingKey": "5", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 2 + }, + "targetingKey": "6", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 1 + }, + "targetingKey": "7", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 1 + }, + "targetingKey": "8", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 2 + }, + "targetingKey": "9", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 2 + }, + "targetingKey": "10", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 1 + }, + "targetingKey": "11", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 1 + }, + "targetingKey": "12", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 2 + }, + "targetingKey": "13", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 1 + }, + "targetingKey": "14", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 2 + }, + "targetingKey": "15", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 2 + }, + "targetingKey": "16", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 1 + }, + "targetingKey": "17", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 1 + }, + "targetingKey": "18", + "variationType": "INTEGER" + }, + { + "attributes": {}, + "defaultValue": 0, + "flag": "integer-flag", + "result": { + "reason": "SPLIT", + "value": 1 + }, + "targetingKey": "19", + "variationType": "INTEGER" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-kill-switch-flag.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-kill-switch-flag.json new file mode 100644 index 00000000000..3af700dc711 --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-kill-switch-flag.json @@ -0,0 +1,314 @@ +[ + { + "attributes": { + "country": "US", + "email": "alice@mycompany.com" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "TARGETING_MATCH", + "value": true + }, + "targetingKey": "alice", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "country": "Canada", + "email": "bob@example.com" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "TARGETING_MATCH", + "value": true + }, + "targetingKey": "bob", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "country": "canada", + "email": "barbara@example.com" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "STATIC", + "value": false + }, + "targetingKey": "barbara", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "age": 40 + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "STATIC", + "value": false + }, + "targetingKey": "charlie", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "age": 25, + "country": "Mexico", + "email": "test@test.com" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "TARGETING_MATCH", + "value": true + }, + "targetingKey": "debra", + "variationType": "BOOLEAN" + }, + { + "attributes": {}, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "STATIC", + "value": false + }, + "targetingKey": "1", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "country": "Mexico" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "TARGETING_MATCH", + "value": true + }, + "targetingKey": "2", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "age": 50, + "country": "UK" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "TARGETING_MATCH", + "value": true + }, + "targetingKey": "3", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "country": "Germany" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "STATIC", + "value": false + }, + "targetingKey": "4", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "country": "Germany" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "STATIC", + "value": false + }, + "targetingKey": "5", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "country": "Germany" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "STATIC", + "value": false + }, + "targetingKey": "6", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "age": 12, + "country": "US" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "TARGETING_MATCH", + "value": true + }, + "targetingKey": "7", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "age": 60, + "country": "Italy" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "TARGETING_MATCH", + "value": true + }, + "targetingKey": "8", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "email": "email@email.com" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "STATIC", + "value": false + }, + "targetingKey": "9", + "variationType": "BOOLEAN" + }, + { + "attributes": {}, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "STATIC", + "value": false + }, + "targetingKey": "10", + "variationType": "BOOLEAN" + }, + { + "attributes": {}, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "STATIC", + "value": false + }, + "targetingKey": "11", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "country": "US" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "TARGETING_MATCH", + "value": true + }, + "targetingKey": "12", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "country": "Canada" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "TARGETING_MATCH", + "value": true + }, + "targetingKey": "13", + "variationType": "BOOLEAN" + }, + { + "attributes": {}, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "STATIC", + "value": false + }, + "targetingKey": "14", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "country": "Denmark" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "STATIC", + "value": false + }, + "targetingKey": "15", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "country": "Norway" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "STATIC", + "value": false + }, + "targetingKey": "16", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "country": "UK" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "STATIC", + "value": false + }, + "targetingKey": "17", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "country": "UK" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "STATIC", + "value": false + }, + "targetingKey": "18", + "variationType": "BOOLEAN" + }, + { + "attributes": { + "country": "UK" + }, + "defaultValue": false, + "flag": "kill-switch", + "result": { + "reason": "STATIC", + "value": false + }, + "targetingKey": "19", + "variationType": "BOOLEAN" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-microsecond-date-flag.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-microsecond-date-flag.json new file mode 100644 index 00000000000..a7bfab410c1 --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-microsecond-date-flag.json @@ -0,0 +1,39 @@ +[ + { + "attributes": {}, + "defaultValue": "unknown", + "flag": "microsecond-date-test", + "result": { + "reason": "STATIC", + "value": "active" + }, + "targetingKey": "alice", + "variationType": "STRING" + }, + { + "attributes": { + "country": "US" + }, + "defaultValue": "unknown", + "flag": "microsecond-date-test", + "result": { + "reason": "STATIC", + "value": "active" + }, + "targetingKey": "bob", + "variationType": "STRING" + }, + { + "attributes": { + "version": "1.0.0" + }, + "defaultValue": "unknown", + "flag": "microsecond-date-test", + "result": { + "reason": "STATIC", + "value": "active" + }, + "targetingKey": "charlie", + "variationType": "STRING" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-new-user-onboarding-flag.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-new-user-onboarding-flag.json new file mode 100644 index 00000000000..bb08523de4e --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-new-user-onboarding-flag.json @@ -0,0 +1,344 @@ +[ + { + "attributes": { + "country": "US", + "email": "alice@mycompany.com" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "TARGETING_MATCH", + "value": "green" + }, + "targetingKey": "alice", + "variationType": "STRING" + }, + { + "attributes": { + "country": "Canada", + "email": "bob@example.com" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "DEFAULT", + "value": "default" + }, + "targetingKey": "bob", + "variationType": "STRING" + }, + { + "attributes": { + "age": 50 + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "DEFAULT", + "value": "default" + }, + "targetingKey": "charlie", + "variationType": "STRING" + }, + { + "attributes": { + "age": 25, + "country": "Mexico", + "email": "test@test.com" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "TARGETING_MATCH", + "value": "blue" + }, + "targetingKey": "debra", + "variationType": "STRING" + }, + { + "attributes": { + "age": 25, + "country": "Mexico", + "email": "test@test.com" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "TARGETING_MATCH", + "value": "purple" + }, + "targetingKey": "zach", + "variationType": "STRING" + }, + { + "attributes": { + "age": 25, + "country": "Mexico", + "email": "test@test.com", + "id": "override-id" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "TARGETING_MATCH", + "value": "blue" + }, + "targetingKey": "zach", + "variationType": "STRING" + }, + { + "attributes": { + "age": 25, + "country": "Mexico", + "email": "test@test.com" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "DEFAULT", + "value": "default" + }, + "targetingKey": "Zach", + "variationType": "STRING" + }, + { + "attributes": {}, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "DEFAULT", + "value": "default" + }, + "targetingKey": "1", + "variationType": "STRING" + }, + { + "attributes": { + "country": "Mexico" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "TARGETING_MATCH", + "value": "blue" + }, + "targetingKey": "2", + "variationType": "STRING" + }, + { + "attributes": { + "age": 33, + "country": "UK" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "TARGETING_MATCH", + "value": "control" + }, + "targetingKey": "3", + "variationType": "STRING" + }, + { + "attributes": { + "country": "Germany" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "TARGETING_MATCH", + "value": "red" + }, + "targetingKey": "4", + "variationType": "STRING" + }, + { + "attributes": { + "country": "Germany" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "TARGETING_MATCH", + "value": "yellow" + }, + "targetingKey": "5", + "variationType": "STRING" + }, + { + "attributes": { + "country": "Germany" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "TARGETING_MATCH", + "value": "yellow" + }, + "targetingKey": "6", + "variationType": "STRING" + }, + { + "attributes": { + "country": "US" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "TARGETING_MATCH", + "value": "blue" + }, + "targetingKey": "7", + "variationType": "STRING" + }, + { + "attributes": { + "country": "Italy" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "TARGETING_MATCH", + "value": "red" + }, + "targetingKey": "8", + "variationType": "STRING" + }, + { + "attributes": { + "email": "email@email.com" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "DEFAULT", + "value": "default" + }, + "targetingKey": "9", + "variationType": "STRING" + }, + { + "attributes": {}, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "DEFAULT", + "value": "default" + }, + "targetingKey": "10", + "variationType": "STRING" + }, + { + "attributes": {}, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "DEFAULT", + "value": "default" + }, + "targetingKey": "11", + "variationType": "STRING" + }, + { + "attributes": { + "country": "US" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "TARGETING_MATCH", + "value": "blue" + }, + "targetingKey": "12", + "variationType": "STRING" + }, + { + "attributes": { + "country": "Canada" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "TARGETING_MATCH", + "value": "blue" + }, + "targetingKey": "13", + "variationType": "STRING" + }, + { + "attributes": {}, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "DEFAULT", + "value": "default" + }, + "targetingKey": "14", + "variationType": "STRING" + }, + { + "attributes": { + "country": "Denmark" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "TARGETING_MATCH", + "value": "yellow" + }, + "targetingKey": "15", + "variationType": "STRING" + }, + { + "attributes": { + "country": "Norway" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "TARGETING_MATCH", + "value": "control" + }, + "targetingKey": "16", + "variationType": "STRING" + }, + { + "attributes": { + "country": "UK" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "TARGETING_MATCH", + "value": "control" + }, + "targetingKey": "17", + "variationType": "STRING" + }, + { + "attributes": { + "country": "UK" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "DEFAULT", + "value": "default" + }, + "targetingKey": "18", + "variationType": "STRING" + }, + { + "attributes": { + "country": "UK" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "TARGETING_MATCH", + "value": "red" + }, + "targetingKey": "19", + "variationType": "STRING" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-no-allocations-flag.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-no-allocations-flag.json new file mode 100644 index 00000000000..7d985b8efd4 --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-no-allocations-flag.json @@ -0,0 +1,55 @@ +[ + { + "attributes": { + "country": "US", + "email": "alice@mycompany.com" + }, + "defaultValue": { + "hello": "world" + }, + "flag": "no_allocations_flag", + "result": { + "reason": "DEFAULT", + "value": { + "hello": "world" + } + }, + "targetingKey": "alice", + "variationType": "JSON" + }, + { + "attributes": { + "country": "Canada", + "email": "bob@example.com" + }, + "defaultValue": { + "hello": "world" + }, + "flag": "no_allocations_flag", + "result": { + "reason": "DEFAULT", + "value": { + "hello": "world" + } + }, + "targetingKey": "bob", + "variationType": "JSON" + }, + { + "attributes": { + "age": 50 + }, + "defaultValue": { + "hello": "world" + }, + "flag": "no_allocations_flag", + "result": { + "reason": "DEFAULT", + "value": { + "hello": "world" + } + }, + "targetingKey": "charlie", + "variationType": "JSON" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-null-operator-flag.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-null-operator-flag.json new file mode 100644 index 00000000000..8063ff8fee3 --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-null-operator-flag.json @@ -0,0 +1,69 @@ +[ + { + "attributes": { + "country": "US", + "size": 5 + }, + "defaultValue": "default-null", + "flag": "null-operator-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "old" + }, + "targetingKey": "alice", + "variationType": "STRING" + }, + { + "attributes": { + "country": "Canada", + "size": 10 + }, + "defaultValue": "default-null", + "flag": "null-operator-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "new" + }, + "targetingKey": "bob", + "variationType": "STRING" + }, + { + "attributes": { + "size": null + }, + "defaultValue": "default-null", + "flag": "null-operator-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "old" + }, + "targetingKey": "charlie", + "variationType": "STRING" + }, + { + "attributes": { + "size": 26 + }, + "defaultValue": "default-null", + "flag": "null-operator-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "new" + }, + "targetingKey": "david", + "variationType": "STRING" + }, + { + "attributes": { + "country": "UK" + }, + "defaultValue": "default-null", + "flag": "null-operator-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "old" + }, + "targetingKey": "elize", + "variationType": "STRING" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-numeric-flag.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-numeric-flag.json new file mode 100644 index 00000000000..cc52dcdff4d --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-numeric-flag.json @@ -0,0 +1,43 @@ +[ + { + "attributes": { + "country": "US", + "email": "alice@mycompany.com" + }, + "defaultValue": 0, + "flag": "numeric_flag", + "result": { + "reason": "STATIC", + "value": 3.1415926 + }, + "targetingKey": "alice", + "variationType": "NUMERIC" + }, + { + "attributes": { + "country": "Canada", + "email": "bob@example.com" + }, + "defaultValue": 0, + "flag": "numeric_flag", + "result": { + "reason": "STATIC", + "value": 3.1415926 + }, + "targetingKey": "bob", + "variationType": "NUMERIC" + }, + { + "attributes": { + "age": 50 + }, + "defaultValue": 0, + "flag": "numeric_flag", + "result": { + "reason": "STATIC", + "value": 3.1415926 + }, + "targetingKey": "charlie", + "variationType": "NUMERIC" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-numeric-one-of.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-numeric-one-of.json new file mode 100644 index 00000000000..bfa957335d3 --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-numeric-one-of.json @@ -0,0 +1,93 @@ +[ + { + "attributes": { + "number": 1 + }, + "defaultValue": 0, + "flag": "numeric-one-of", + "result": { + "reason": "TARGETING_MATCH", + "value": 1 + }, + "targetingKey": "alice", + "variationType": "INTEGER" + }, + { + "attributes": { + "number": 2 + }, + "defaultValue": 0, + "flag": "numeric-one-of", + "result": { + "reason": "DEFAULT", + "value": 0 + }, + "targetingKey": "bob", + "variationType": "INTEGER" + }, + { + "attributes": { + "number": 3 + }, + "defaultValue": 0, + "flag": "numeric-one-of", + "result": { + "reason": "TARGETING_MATCH", + "value": 3 + }, + "targetingKey": "charlie", + "variationType": "INTEGER" + }, + { + "attributes": { + "number": 4 + }, + "defaultValue": 0, + "flag": "numeric-one-of", + "result": { + "reason": "TARGETING_MATCH", + "value": 3 + }, + "targetingKey": "derek", + "variationType": "INTEGER" + }, + { + "attributes": { + "number": "1" + }, + "defaultValue": 0, + "flag": "numeric-one-of", + "result": { + "reason": "TARGETING_MATCH", + "value": 1 + }, + "targetingKey": "erica", + "variationType": "INTEGER" + }, + { + "attributes": { + "number": 1 + }, + "defaultValue": 0, + "flag": "numeric-one-of", + "result": { + "reason": "TARGETING_MATCH", + "value": 1 + }, + "targetingKey": "frank", + "variationType": "INTEGER" + }, + { + "attributes": { + "number": 123456789 + }, + "defaultValue": 0, + "flag": "numeric-one-of", + "result": { + "reason": "TARGETING_MATCH", + "value": 2 + }, + "targetingKey": "george", + "variationType": "INTEGER" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-of-7-empty-targeting-key.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-of-7-empty-targeting-key.json new file mode 100644 index 00000000000..e99a207b6da --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-of-7-empty-targeting-key.json @@ -0,0 +1,13 @@ +[ + { + "attributes": {}, + "defaultValue": "default", + "flag": "empty-targeting-key-flag", + "result": { + "reason": "STATIC", + "value": "on-value" + }, + "targetingKey": "", + "variationType": "STRING" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-regex-flag.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-regex-flag.json new file mode 100644 index 00000000000..253c4f7caca --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-regex-flag.json @@ -0,0 +1,57 @@ +[ + { + "attributes": { + "email": "alice@example.com", + "version": "1.15.0" + }, + "defaultValue": "none", + "flag": "regex-flag", + "result": { + "reason": "TARGETING_MATCH", + "value": "partial-example" + }, + "targetingKey": "alice", + "variationType": "STRING" + }, + { + "attributes": { + "email": "bob@test.com", + "version": "0.20.1" + }, + "defaultValue": "none", + "flag": "regex-flag", + "result": { + "reason": "TARGETING_MATCH", + "value": "test" + }, + "targetingKey": "bob", + "variationType": "STRING" + }, + { + "attributes": { + "version": "2.1.13" + }, + "defaultValue": "none", + "flag": "regex-flag", + "result": { + "reason": "DEFAULT", + "value": "none" + }, + "targetingKey": "charlie", + "variationType": "STRING" + }, + { + "attributes": { + "email": "derek@gmail.com", + "version": "2.1.13" + }, + "defaultValue": "none", + "flag": "regex-flag", + "result": { + "reason": "DEFAULT", + "value": "none" + }, + "targetingKey": "derek", + "variationType": "STRING" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-start-and-end-date-flag.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-start-and-end-date-flag.json new file mode 100644 index 00000000000..0ab6dbd681d --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-case-start-and-end-date-flag.json @@ -0,0 +1,43 @@ +[ + { + "attributes": { + "country": "US", + "version": "1.15.0" + }, + "defaultValue": "unknown", + "flag": "start-and-end-date-test", + "result": { + "reason": "STATIC", + "value": "current" + }, + "targetingKey": "alice", + "variationType": "STRING" + }, + { + "attributes": { + "country": "Canada", + "version": "0.20.1" + }, + "defaultValue": "unknown", + "flag": "start-and-end-date-test", + "result": { + "reason": "STATIC", + "value": "current" + }, + "targetingKey": "bob", + "variationType": "STRING" + }, + { + "attributes": { + "version": "2.1.13" + }, + "defaultValue": "unknown", + "flag": "start-and-end-date-test", + "result": { + "reason": "STATIC", + "value": "current" + }, + "targetingKey": "charlie", + "variationType": "STRING" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-flag-that-does-not-exist.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-flag-that-does-not-exist.json new file mode 100644 index 00000000000..453beb7290c --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-flag-that-does-not-exist.json @@ -0,0 +1,43 @@ +[ + { + "attributes": { + "country": "US", + "email": "alice@mycompany.com" + }, + "defaultValue": 0, + "flag": "flag-that-does-not-exist", + "result": { + "reason": "DEFAULT", + "value": 0 + }, + "targetingKey": "alice", + "variationType": "NUMERIC" + }, + { + "attributes": { + "country": "Canada", + "email": "bob@example.com" + }, + "defaultValue": 0, + "flag": "flag-that-does-not-exist", + "result": { + "reason": "DEFAULT", + "value": 0 + }, + "targetingKey": "bob", + "variationType": "NUMERIC" + }, + { + "attributes": { + "age": 50 + }, + "defaultValue": 0, + "flag": "flag-that-does-not-exist", + "result": { + "reason": "DEFAULT", + "value": 0 + }, + "targetingKey": "charlie", + "variationType": "NUMERIC" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-json-config-flag.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-json-config-flag.json new file mode 100644 index 00000000000..aef944c93a6 --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-json-config-flag.json @@ -0,0 +1,76 @@ +[ + { + "attributes": { + "country": "US", + "email": "alice@mycompany.com" + }, + "defaultValue": { + "foo": "bar" + }, + "flag": "json-config-flag", + "result": { + "reason": "SPLIT", + "value": { + "float": 1, + "integer": 1, + "string": "one" + } + }, + "targetingKey": "alice", + "variationType": "JSON" + }, + { + "attributes": { + "country": "Canada", + "email": "bob@example.com" + }, + "defaultValue": { + "foo": "bar" + }, + "flag": "json-config-flag", + "result": { + "reason": "SPLIT", + "value": { + "float": 2, + "integer": 2, + "string": "two" + } + }, + "targetingKey": "bob", + "variationType": "JSON" + }, + { + "attributes": { + "age": 50 + }, + "defaultValue": { + "foo": "bar" + }, + "flag": "json-config-flag", + "result": { + "reason": "SPLIT", + "value": { + "float": 2, + "integer": 2, + "string": "two" + } + }, + "targetingKey": "charlie", + "variationType": "JSON" + }, + { + "attributes": { + "Force Empty": true + }, + "defaultValue": { + "foo": "bar" + }, + "flag": "json-config-flag", + "result": { + "reason": "TARGETING_MATCH", + "value": {} + }, + "targetingKey": "diana", + "variationType": "JSON" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-no-allocations-flag.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-no-allocations-flag.json new file mode 100644 index 00000000000..2b03b9a39a1 --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-no-allocations-flag.json @@ -0,0 +1,55 @@ +[ + { + "attributes": { + "country": "US", + "email": "alice@mycompany.com" + }, + "defaultValue": { + "message": "Hello, world!" + }, + "flag": "no_allocations_flag", + "result": { + "reason": "DEFAULT", + "value": { + "message": "Hello, world!" + } + }, + "targetingKey": "alice", + "variationType": "JSON" + }, + { + "attributes": { + "country": "Canada", + "email": "bob@example.com" + }, + "defaultValue": { + "message": "Hello, world!" + }, + "flag": "no_allocations_flag", + "result": { + "reason": "DEFAULT", + "value": { + "message": "Hello, world!" + } + }, + "targetingKey": "bob", + "variationType": "JSON" + }, + { + "attributes": { + "age": 50 + }, + "defaultValue": { + "message": "Hello, world!" + }, + "flag": "no_allocations_flag", + "result": { + "reason": "DEFAULT", + "value": { + "message": "Hello, world!" + } + }, + "targetingKey": "charlie", + "variationType": "JSON" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-special-characters.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-special-characters.json new file mode 100644 index 00000000000..1ed7795bb95 --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-special-characters.json @@ -0,0 +1,58 @@ +[ + { + "attributes": {}, + "defaultValue": {}, + "flag": "special-characters", + "result": { + "reason": "SPLIT", + "value": { + "a": "kümmert", + "b": "schön" + } + }, + "targetingKey": "ash", + "variationType": "JSON" + }, + { + "attributes": {}, + "defaultValue": {}, + "flag": "special-characters", + "result": { + "reason": "SPLIT", + "value": { + "a": "піклуватися", + "b": "любов" + } + }, + "targetingKey": "ben", + "variationType": "JSON" + }, + { + "attributes": {}, + "defaultValue": {}, + "flag": "special-characters", + "result": { + "reason": "SPLIT", + "value": { + "a": "照顾", + "b": "漂亮" + } + }, + "targetingKey": "cameron", + "variationType": "JSON" + }, + { + "attributes": {}, + "defaultValue": {}, + "flag": "special-characters", + "result": { + "reason": "SPLIT", + "value": { + "a": "🤗", + "b": "🌸" + } + }, + "targetingKey": "darryl", + "variationType": "JSON" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-string-with-special-characters.json b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-string-with-special-characters.json new file mode 100644 index 00000000000..32397a48398 --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/evaluation-cases/test-string-with-special-characters.json @@ -0,0 +1,860 @@ +[ + { + "attributes": { + "string_with_spaces": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": " a b c d e f " + }, + "targetingKey": "string_with_spaces", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_space": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": " " + }, + "targetingKey": "string_with_only_one_space", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_spaces": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": " " + }, + "targetingKey": "string_with_only_multiple_spaces", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_dots": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": ".a.b.c.d.e.f." + }, + "targetingKey": "string_with_dots", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_dot": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "." + }, + "targetingKey": "string_with_only_one_dot", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_dots": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "......." + }, + "targetingKey": "string_with_only_multiple_dots", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_comas": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": ",a,b,c,d,e,f," + }, + "targetingKey": "string_with_comas", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_coma": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "," + }, + "targetingKey": "string_with_only_one_coma", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_comas": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": ",,,,,,," + }, + "targetingKey": "string_with_only_multiple_comas", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_colons": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": ":a:b:c:d:e:f:" + }, + "targetingKey": "string_with_colons", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_colon": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": ":" + }, + "targetingKey": "string_with_only_one_colon", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_colons": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": ":::::::" + }, + "targetingKey": "string_with_only_multiple_colons", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_semicolons": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": ";a;b;c;d;e;f;" + }, + "targetingKey": "string_with_semicolons", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_semicolon": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": ";" + }, + "targetingKey": "string_with_only_one_semicolon", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_semicolons": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": ";;;;;;;" + }, + "targetingKey": "string_with_only_multiple_semicolons", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_slashes": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "/a/b/c/d/e/f/" + }, + "targetingKey": "string_with_slashes", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_slash": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "/" + }, + "targetingKey": "string_with_only_one_slash", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_slashes": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "///////" + }, + "targetingKey": "string_with_only_multiple_slashes", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_dashes": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "-a-b-c-d-e-f-" + }, + "targetingKey": "string_with_dashes", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_dash": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "-" + }, + "targetingKey": "string_with_only_one_dash", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_dashes": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "-------" + }, + "targetingKey": "string_with_only_multiple_dashes", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_underscores": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "_a_b_c_d_e_f_" + }, + "targetingKey": "string_with_underscores", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_underscore": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "_" + }, + "targetingKey": "string_with_only_one_underscore", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_underscores": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "_______" + }, + "targetingKey": "string_with_only_multiple_underscores", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_plus_signs": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "+a+b+c+d+e+f+" + }, + "targetingKey": "string_with_plus_signs", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_plus_sign": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "+" + }, + "targetingKey": "string_with_only_one_plus_sign", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_plus_signs": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "+++++++" + }, + "targetingKey": "string_with_only_multiple_plus_signs", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_equal_signs": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "=a=b=c=d=e=f=" + }, + "targetingKey": "string_with_equal_signs", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_equal_sign": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "=" + }, + "targetingKey": "string_with_only_one_equal_sign", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_equal_signs": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "=======" + }, + "targetingKey": "string_with_only_multiple_equal_signs", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_dollar_signs": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "$a$b$c$d$e$f$" + }, + "targetingKey": "string_with_dollar_signs", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_dollar_sign": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "$" + }, + "targetingKey": "string_with_only_one_dollar_sign", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_dollar_signs": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "$$$$$$$" + }, + "targetingKey": "string_with_only_multiple_dollar_signs", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_at_signs": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "@a@b@c@d@e@f@" + }, + "targetingKey": "string_with_at_signs", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_at_sign": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "@" + }, + "targetingKey": "string_with_only_one_at_sign", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_at_signs": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "@@@@@@@" + }, + "targetingKey": "string_with_only_multiple_at_signs", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_amp_signs": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "\u0026a\u0026b\u0026c\u0026d\u0026e\u0026f\u0026" + }, + "targetingKey": "string_with_amp_signs", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_amp_sign": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "\u0026" + }, + "targetingKey": "string_with_only_one_amp_sign", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_amp_signs": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "\u0026\u0026\u0026\u0026\u0026\u0026\u0026" + }, + "targetingKey": "string_with_only_multiple_amp_signs", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_hash_signs": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "#a#b#c#d#e#f#" + }, + "targetingKey": "string_with_hash_signs", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_hash_sign": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "#" + }, + "targetingKey": "string_with_only_one_hash_sign", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_hash_signs": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "#######" + }, + "targetingKey": "string_with_only_multiple_hash_signs", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_percentage_signs": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "%a%b%c%d%e%f%" + }, + "targetingKey": "string_with_percentage_signs", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_percentage_sign": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "%" + }, + "targetingKey": "string_with_only_one_percentage_sign", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_percentage_signs": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "%%%%%%%" + }, + "targetingKey": "string_with_only_multiple_percentage_signs", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_tilde_signs": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "~a~b~c~d~e~f~" + }, + "targetingKey": "string_with_tilde_signs", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_tilde_sign": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "~" + }, + "targetingKey": "string_with_only_one_tilde_sign", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_tilde_signs": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "~~~~~~~" + }, + "targetingKey": "string_with_only_multiple_tilde_signs", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_asterix_signs": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "*a*b*c*d*e*f*" + }, + "targetingKey": "string_with_asterix_signs", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_asterix_sign": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "*" + }, + "targetingKey": "string_with_only_one_asterix_sign", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_asterix_signs": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "*******" + }, + "targetingKey": "string_with_only_multiple_asterix_signs", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_single_quotes": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "'a'b'c'd'e'f'" + }, + "targetingKey": "string_with_single_quotes", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_single_quote": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "'" + }, + "targetingKey": "string_with_only_one_single_quote", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_single_quotes": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "'''''''" + }, + "targetingKey": "string_with_only_multiple_single_quotes", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_question_marks": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "?a?b?c?d?e?f?" + }, + "targetingKey": "string_with_question_marks", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_question_mark": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "?" + }, + "targetingKey": "string_with_only_one_question_mark", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_question_marks": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "???????" + }, + "targetingKey": "string_with_only_multiple_question_marks", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_exclamation_marks": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "!a!b!c!d!e!f!" + }, + "targetingKey": "string_with_exclamation_marks", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_exclamation_mark": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "!" + }, + "targetingKey": "string_with_only_one_exclamation_mark", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_exclamation_marks": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "!!!!!!!" + }, + "targetingKey": "string_with_only_multiple_exclamation_marks", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_opening_parentheses": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "(a(b(c(d(e(f(" + }, + "targetingKey": "string_with_opening_parentheses", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_opening_parenthese": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "(" + }, + "targetingKey": "string_with_only_one_opening_parenthese", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_opening_parentheses": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": "(((((((" + }, + "targetingKey": "string_with_only_multiple_opening_parentheses", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_closing_parentheses": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": ")a)b)c)d)e)f)" + }, + "targetingKey": "string_with_closing_parentheses", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_one_closing_parenthese": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": ")" + }, + "targetingKey": "string_with_only_one_closing_parenthese", + "variationType": "STRING" + }, + { + "attributes": { + "string_with_only_multiple_closing_parentheses": true + }, + "defaultValue": "default_value", + "flag": "string_flag_with_special_characters", + "result": { + "reason": "TARGETING_MATCH", + "value": ")))))))" + }, + "targetingKey": "string_with_only_multiple_closing_parentheses", + "variationType": "STRING" + } +] diff --git a/products/feature-flagging/feature-flagging-api/src/test/resources/ufc-config.json b/products/feature-flagging/feature-flagging-api/src/test/resources/ufc-config.json new file mode 100644 index 00000000000..6c9a18e2996 --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/resources/ufc-config.json @@ -0,0 +1,3353 @@ +{ + "createdAt": "2024-04-17T19:40:53.716Z", + "format": "SERVER", + "environment": { + "name": "Test" + }, + "flags": { + "empty_flag": { + "key": "empty_flag", + "enabled": true, + "variationType": "STRING", + "variations": {}, + "allocations": [] + }, + "disabled_flag": { + "key": "disabled_flag", + "enabled": false, + "variationType": "INTEGER", + "variations": {}, + "allocations": [] + }, + "no_allocations_flag": { + "key": "no_allocations_flag", + "enabled": true, + "variationType": "JSON", + "variations": { + "control": { + "key": "control", + "value": { + "variant": "control" + } + }, + "treatment": { + "key": "treatment", + "value": { + "variant": "treatment" + } + } + }, + "allocations": [] + }, + "numeric_flag": { + "key": "numeric_flag", + "enabled": true, + "variationType": "NUMERIC", + "variations": { + "e": { + "key": "e", + "value": 2.7182818 + }, + "pi": { + "key": "pi", + "value": 3.1415926 + } + }, + "allocations": [ + { + "key": "rollout", + "splits": [ + { + "variationKey": "pi", + "shards": [] + } + ], + "doLog": true + } + ] + }, + "regex-flag": { + "key": "regex-flag", + "enabled": true, + "variationType": "STRING", + "variations": { + "partial-example": { + "key": "partial-example", + "value": "partial-example" + }, + "test": { + "key": "test", + "value": "test" + } + }, + "allocations": [ + { + "key": "partial-example", + "rules": [ + { + "conditions": [ + { + "attribute": "email", + "operator": "MATCHES", + "value": "@example\\.com" + } + ] + } + ], + "splits": [ + { + "variationKey": "partial-example", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "test", + "rules": [ + { + "conditions": [ + { + "attribute": "email", + "operator": "MATCHES", + "value": ".*@test\\.com" + } + ] + } + ], + "splits": [ + { + "variationKey": "test", + "shards": [] + } + ], + "doLog": true + } + ] + }, + "numeric-one-of": { + "key": "numeric-one-of", + "enabled": true, + "variationType": "INTEGER", + "variations": { + "1": { + "key": "1", + "value": 1 + }, + "2": { + "key": "2", + "value": 2 + }, + "3": { + "key": "3", + "value": 3 + } + }, + "allocations": [ + { + "key": "1-for-1", + "rules": [ + { + "conditions": [ + { + "attribute": "number", + "operator": "ONE_OF", + "value": [ + "1" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "1", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "2-for-123456789", + "rules": [ + { + "conditions": [ + { + "attribute": "number", + "operator": "ONE_OF", + "value": [ + "123456789" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "2", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "3-for-not-2", + "rules": [ + { + "conditions": [ + { + "attribute": "number", + "operator": "NOT_ONE_OF", + "value": [ + "2" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "3", + "shards": [] + } + ], + "doLog": true + } + ] + }, + "boolean-one-of-matches": { + "key": "boolean-one-of-matches", + "enabled": true, + "variationType": "INTEGER", + "variations": { + "1": { + "key": "1", + "value": 1 + }, + "2": { + "key": "2", + "value": 2 + }, + "3": { + "key": "3", + "value": 3 + }, + "4": { + "key": "4", + "value": 4 + }, + "5": { + "key": "5", + "value": 5 + } + }, + "allocations": [ + { + "key": "1-for-one-of", + "rules": [ + { + "conditions": [ + { + "attribute": "one_of_flag", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "1", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "2-for-matches", + "rules": [ + { + "conditions": [ + { + "attribute": "matches_flag", + "operator": "MATCHES", + "value": "true" + } + ] + } + ], + "splits": [ + { + "variationKey": "2", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "3-for-not-one-of", + "rules": [ + { + "conditions": [ + { + "attribute": "not_one_of_flag", + "operator": "NOT_ONE_OF", + "value": [ + "false" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "3", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "4-for-not-matches", + "rules": [ + { + "conditions": [ + { + "attribute": "not_matches_flag", + "operator": "NOT_MATCHES", + "value": "false" + } + ] + } + ], + "splits": [ + { + "variationKey": "4", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "5-for-matches-null", + "rules": [ + { + "conditions": [ + { + "attribute": "null_flag", + "operator": "ONE_OF", + "value": [ + "null" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "5", + "shards": [] + } + ], + "doLog": true + } + ] + }, + "empty_string_flag": { + "key": "empty_string_flag", + "enabled": true, + "comment": "Testing the empty string as a variation value", + "variationType": "STRING", + "variations": { + "empty_string": { + "key": "empty_string", + "value": "" + }, + "non_empty": { + "key": "non_empty", + "value": "non_empty" + } + }, + "allocations": [ + { + "key": "allocation-empty", + "rules": [ + { + "conditions": [ + { + "attribute": "country", + "operator": "MATCHES", + "value": "US" + } + ] + } + ], + "splits": [ + { + "variationKey": "empty_string", + "shards": [ + { + "salt": "allocation-empty-shards", + "totalShards": 10000, + "ranges": [ + { + "start": 0, + "end": 10000 + } + ] + } + ] + } + ], + "doLog": true + }, + { + "key": "allocation-test", + "rules": [], + "splits": [ + { + "variationKey": "non_empty", + "shards": [ + { + "salt": "allocation-empty-shards", + "totalShards": 10000, + "ranges": [ + { + "start": 0, + "end": 10000 + } + ] + } + ] + } + ], + "doLog": true + } + ] + }, + "kill-switch": { + "key": "kill-switch", + "enabled": true, + "variationType": "BOOLEAN", + "variations": { + "on": { + "key": "on", + "value": true + }, + "off": { + "key": "off", + "value": false + } + }, + "allocations": [ + { + "key": "on-for-NA", + "rules": [ + { + "conditions": [ + { + "attribute": "country", + "operator": "ONE_OF", + "value": [ + "US", + "Canada", + "Mexico" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "on", + "shards": [ + { + "salt": "some-salt", + "totalShards": 10000, + "ranges": [ + { + "start": 0, + "end": 10000 + } + ] + } + ] + } + ], + "doLog": true + }, + { + "key": "on-for-age-50+", + "rules": [ + { + "conditions": [ + { + "attribute": "age", + "operator": "GTE", + "value": 50 + } + ] + } + ], + "splits": [ + { + "variationKey": "on", + "shards": [ + { + "salt": "some-salt", + "totalShards": 10000, + "ranges": [ + { + "start": 0, + "end": 10000 + } + ] + } + ] + } + ], + "doLog": true + }, + { + "key": "off-for-all", + "rules": [], + "splits": [ + { + "variationKey": "off", + "shards": [] + } + ], + "doLog": true + } + ] + }, + "comparator-operator-test": { + "key": "comparator-operator-test", + "enabled": true, + "variationType": "STRING", + "variations": { + "small": { + "key": "small", + "value": "small" + }, + "medium": { + "key": "medium", + "value": "medium" + }, + "large": { + "key": "large", + "value": "large" + } + }, + "allocations": [ + { + "key": "small-size", + "rules": [ + { + "conditions": [ + { + "attribute": "size", + "operator": "LT", + "value": 10 + } + ] + } + ], + "splits": [ + { + "variationKey": "small", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "medum-size", + "rules": [ + { + "conditions": [ + { + "attribute": "size", + "operator": "GTE", + "value": 10 + }, + { + "attribute": "size", + "operator": "LTE", + "value": 20 + } + ] + } + ], + "splits": [ + { + "variationKey": "medium", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "large-size", + "rules": [ + { + "conditions": [ + { + "attribute": "size", + "operator": "GT", + "value": 25 + } + ] + } + ], + "splits": [ + { + "variationKey": "large", + "shards": [] + } + ], + "doLog": true + } + ] + }, + "start-and-end-date-test": { + "key": "start-and-end-date-test", + "enabled": true, + "variationType": "STRING", + "variations": { + "old": { + "key": "old", + "value": "old" + }, + "current": { + "key": "current", + "value": "current" + }, + "new": { + "key": "new", + "value": "new" + } + }, + "allocations": [ + { + "key": "old-versions", + "splits": [ + { + "variationKey": "old", + "shards": [] + } + ], + "endAt": "2002-10-31T09:00:00.594Z", + "doLog": true + }, + { + "key": "future-versions", + "splits": [ + { + "variationKey": "new", + "shards": [] + } + ], + "startAt": "2052-10-31T09:00:00.594Z", + "doLog": true + }, + { + "key": "current-versions", + "splits": [ + { + "variationKey": "current", + "shards": [] + } + ], + "startAt": "2022-10-31T09:00:00.594Z", + "endAt": "2050-10-31T09:00:00.594Z", + "doLog": true + } + ] + }, + "null-operator-test": { + "key": "null-operator-test", + "enabled": true, + "variationType": "STRING", + "variations": { + "old": { + "key": "old", + "value": "old" + }, + "new": { + "key": "new", + "value": "new" + } + }, + "allocations": [ + { + "key": "null-operator", + "rules": [ + { + "conditions": [ + { + "attribute": "size", + "operator": "IS_NULL", + "value": true + } + ] + }, + { + "conditions": [ + { + "attribute": "size", + "operator": "LT", + "value": 10 + } + ] + } + ], + "splits": [ + { + "variationKey": "old", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "not-null-operator", + "rules": [ + { + "conditions": [ + { + "attribute": "size", + "operator": "IS_NULL", + "value": false + } + ] + } + ], + "splits": [ + { + "variationKey": "new", + "shards": [] + } + ], + "doLog": true + } + ] + }, + "new-user-onboarding": { + "key": "new-user-onboarding", + "enabled": true, + "variationType": "STRING", + "variations": { + "control": { + "key": "control", + "value": "control" + }, + "red": { + "key": "red", + "value": "red" + }, + "blue": { + "key": "blue", + "value": "blue" + }, + "green": { + "key": "green", + "value": "green" + }, + "yellow": { + "key": "yellow", + "value": "yellow" + }, + "purple": { + "key": "purple", + "value": "purple" + } + }, + "allocations": [ + { + "key": "id rule", + "rules": [ + { + "conditions": [ + { + "attribute": "id", + "operator": "MATCHES", + "value": "zach" + } + ] + } + ], + "splits": [ + { + "variationKey": "purple", + "shards": [] + } + ], + "doLog": false + }, + { + "key": "internal users", + "rules": [ + { + "conditions": [ + { + "attribute": "email", + "operator": "MATCHES", + "value": "@mycompany.com" + } + ] + } + ], + "splits": [ + { + "variationKey": "green", + "shards": [] + } + ], + "doLog": false + }, + { + "key": "experiment", + "rules": [ + { + "conditions": [ + { + "attribute": "country", + "operator": "NOT_ONE_OF", + "value": [ + "US", + "Canada", + "Mexico" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "control", + "shards": [ + { + "salt": "traffic-new-user-onboarding-experiment", + "totalShards": 10000, + "ranges": [ + { + "start": 0, + "end": 6000 + } + ] + }, + { + "salt": "split-new-user-onboarding-experiment", + "totalShards": 10000, + "ranges": [ + { + "start": 0, + "end": 5000 + } + ] + } + ] + }, + { + "variationKey": "red", + "shards": [ + { + "salt": "traffic-new-user-onboarding-experiment", + "totalShards": 10000, + "ranges": [ + { + "start": 0, + "end": 6000 + } + ] + }, + { + "salt": "split-new-user-onboarding-experiment", + "totalShards": 10000, + "ranges": [ + { + "start": 5000, + "end": 8000 + } + ] + } + ] + }, + { + "variationKey": "yellow", + "shards": [ + { + "salt": "traffic-new-user-onboarding-experiment", + "totalShards": 10000, + "ranges": [ + { + "start": 0, + "end": 6000 + } + ] + }, + { + "salt": "split-new-user-onboarding-experiment", + "totalShards": 10000, + "ranges": [ + { + "start": 8000, + "end": 10000 + } + ] + } + ] + } + ], + "doLog": true + }, + { + "key": "rollout", + "rules": [ + { + "conditions": [ + { + "attribute": "country", + "operator": "ONE_OF", + "value": [ + "US", + "Canada", + "Mexico" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "blue", + "shards": [ + { + "salt": "split-new-user-onboarding-rollout", + "totalShards": 10000, + "ranges": [ + { + "start": 0, + "end": 8000 + } + ] + } + ], + "extraLogging": { + "allocationvalue_type": "rollout", + "owner": "hippo" + } + } + ], + "doLog": true + } + ] + }, + "integer-flag": { + "key": "integer-flag", + "enabled": true, + "variationType": "INTEGER", + "variations": { + "one": { + "key": "one", + "value": 1 + }, + "two": { + "key": "two", + "value": 2 + }, + "three": { + "key": "three", + "value": 3 + } + }, + "allocations": [ + { + "key": "targeted allocation", + "rules": [ + { + "conditions": [ + { + "attribute": "country", + "operator": "ONE_OF", + "value": [ + "US", + "Canada", + "Mexico" + ] + } + ] + }, + { + "conditions": [ + { + "attribute": "email", + "operator": "MATCHES", + "value": ".*@example.com" + } + ] + } + ], + "splits": [ + { + "variationKey": "three", + "shards": [ + { + "salt": "full-range-salt", + "totalShards": 10000, + "ranges": [ + { + "start": 0, + "end": 10000 + } + ] + } + ] + } + ], + "doLog": true + }, + { + "key": "50/50 split", + "rules": [], + "splits": [ + { + "variationKey": "one", + "shards": [ + { + "salt": "split-numeric-flag-some-allocation", + "totalShards": 10000, + "ranges": [ + { + "start": 0, + "end": 5000 + } + ] + } + ] + }, + { + "variationKey": "two", + "shards": [ + { + "salt": "split-numeric-flag-some-allocation", + "totalShards": 10000, + "ranges": [ + { + "start": 5000, + "end": 10000 + } + ] + } + ] + } + ], + "doLog": true + } + ] + }, + "json-config-flag": { + "key": "json-config-flag", + "enabled": true, + "variationType": "JSON", + "variations": { + "one": { + "key": "one", + "value": { + "integer": 1, + "string": "one", + "float": 1.0 + } + }, + "two": { + "key": "two", + "value": { + "integer": 2, + "string": "two", + "float": 2.0 + } + }, + "empty": { + "key": "empty", + "value": {} + } + }, + "allocations": [ + { + "key": "Optionally Force Empty", + "rules": [ + { + "conditions": [ + { + "attribute": "Force Empty", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "empty", + "shards": [ + { + "salt": "full-range-salt", + "totalShards": 10000, + "ranges": [ + { + "start": 0, + "end": 10000 + } + ] + } + ] + } + ], + "doLog": true + }, + { + "key": "50/50 split", + "rules": [], + "splits": [ + { + "variationKey": "one", + "shards": [ + { + "salt": "traffic-json-flag", + "totalShards": 10000, + "ranges": [ + { + "start": 0, + "end": 10000 + } + ] + }, + { + "salt": "split-json-flag", + "totalShards": 10000, + "ranges": [ + { + "start": 0, + "end": 5000 + } + ] + } + ] + }, + { + "variationKey": "two", + "shards": [ + { + "salt": "traffic-json-flag", + "totalShards": 10000, + "ranges": [ + { + "start": 0, + "end": 10000 + } + ] + }, + { + "salt": "split-json-flag", + "totalShards": 10000, + "ranges": [ + { + "start": 5000, + "end": 10000 + } + ] + } + ] + } + ], + "doLog": true + } + ] + }, + "special-characters": { + "key": "special-characters", + "enabled": true, + "variationType": "JSON", + "variations": { + "de": { + "key": "de", + "value": { + "a": "kümmert", + "b": "schön" + } + }, + "ua": { + "key": "ua", + "value": { + "a": "піклуватися", + "b": "любов" + } + }, + "zh": { + "key": "zh", + "value": { + "a": "照顾", + "b": "漂亮" + } + }, + "emoji": { + "key": "emoji", + "value": { + "a": "🤗", + "b": "🌸" + } + } + }, + "allocations": [ + { + "key": "allocation-test", + "splits": [ + { + "variationKey": "de", + "shards": [ + { + "salt": "split-json-flag", + "totalShards": 10000, + "ranges": [ + { + "start": 0, + "end": 2500 + } + ] + } + ] + }, + { + "variationKey": "ua", + "shards": [ + { + "salt": "split-json-flag", + "totalShards": 10000, + "ranges": [ + { + "start": 2500, + "end": 5000 + } + ] + } + ] + }, + { + "variationKey": "zh", + "shards": [ + { + "salt": "split-json-flag", + "totalShards": 10000, + "ranges": [ + { + "start": 5000, + "end": 7500 + } + ] + } + ] + }, + { + "variationKey": "emoji", + "shards": [ + { + "salt": "split-json-flag", + "totalShards": 10000, + "ranges": [ + { + "start": 7500, + "end": 10000 + } + ] + } + ] + } + ], + "doLog": true + }, + { + "key": "allocation-default", + "splits": [ + { + "variationKey": "de", + "shards": [] + } + ], + "doLog": false + } + ] + }, + "string_flag_with_special_characters": { + "key": "string_flag_with_special_characters", + "enabled": true, + "comment": "Testing the string with special characters and spaces", + "variationType": "STRING", + "variations": { + "string_with_spaces": { + "key": "string_with_spaces", + "value": " a b c d e f " + }, + "string_with_only_one_space": { + "key": "string_with_only_one_space", + "value": " " + }, + "string_with_only_multiple_spaces": { + "key": "string_with_only_multiple_spaces", + "value": " " + }, + "string_with_dots": { + "key": "string_with_dots", + "value": ".a.b.c.d.e.f." + }, + "string_with_only_one_dot": { + "key": "string_with_only_one_dot", + "value": "." + }, + "string_with_only_multiple_dots": { + "key": "string_with_only_multiple_dots", + "value": "......." + }, + "string_with_comas": { + "key": "string_with_comas", + "value": ",a,b,c,d,e,f," + }, + "string_with_only_one_coma": { + "key": "string_with_only_one_coma", + "value": "," + }, + "string_with_only_multiple_comas": { + "key": "string_with_only_multiple_comas", + "value": ",,,,,,," + }, + "string_with_colons": { + "key": "string_with_colons", + "value": ":a:b:c:d:e:f:" + }, + "string_with_only_one_colon": { + "key": "string_with_only_one_colon", + "value": ":" + }, + "string_with_only_multiple_colons": { + "key": "string_with_only_multiple_colons", + "value": ":::::::" + }, + "string_with_semicolons": { + "key": "string_with_semicolons", + "value": ";a;b;c;d;e;f;" + }, + "string_with_only_one_semicolon": { + "key": "string_with_only_one_semicolon", + "value": ";" + }, + "string_with_only_multiple_semicolons": { + "key": "string_with_only_multiple_semicolons", + "value": ";;;;;;;" + }, + "string_with_slashes": { + "key": "string_with_slashes", + "value": "/a/b/c/d/e/f/" + }, + "string_with_only_one_slash": { + "key": "string_with_only_one_slash", + "value": "/" + }, + "string_with_only_multiple_slashes": { + "key": "string_with_only_multiple_slashes", + "value": "///////" + }, + "string_with_dashes": { + "key": "string_with_dashes", + "value": "-a-b-c-d-e-f-" + }, + "string_with_only_one_dash": { + "key": "string_with_only_one_dash", + "value": "-" + }, + "string_with_only_multiple_dashes": { + "key": "string_with_only_multiple_dashes", + "value": "-------" + }, + "string_with_underscores": { + "key": "string_with_underscores", + "value": "_a_b_c_d_e_f_" + }, + "string_with_only_one_underscore": { + "key": "string_with_only_one_underscore", + "value": "_" + }, + "string_with_only_multiple_underscores": { + "key": "string_with_only_multiple_underscores", + "value": "_______" + }, + "string_with_plus_signs": { + "key": "string_with_plus_signs", + "value": "+a+b+c+d+e+f+" + }, + "string_with_only_one_plus_sign": { + "key": "string_with_only_one_plus_sign", + "value": "+" + }, + "string_with_only_multiple_plus_signs": { + "key": "string_with_only_multiple_plus_signs", + "value": "+++++++" + }, + "string_with_equal_signs": { + "key": "string_with_equal_signs", + "value": "=a=b=c=d=e=f=" + }, + "string_with_only_one_equal_sign": { + "key": "string_with_only_one_equal_sign", + "value": "=" + }, + "string_with_only_multiple_equal_signs": { + "key": "string_with_only_multiple_equal_signs", + "value": "=======" + }, + "string_with_dollar_signs": { + "key": "string_with_dollar_signs", + "value": "$a$b$c$d$e$f$" + }, + "string_with_only_one_dollar_sign": { + "key": "string_with_only_one_dollar_sign", + "value": "$" + }, + "string_with_only_multiple_dollar_signs": { + "key": "string_with_only_multiple_dollar_signs", + "value": "$$$$$$$" + }, + "string_with_at_signs": { + "key": "string_with_at_signs", + "value": "@a@b@c@d@e@f@" + }, + "string_with_only_one_at_sign": { + "key": "string_with_only_one_at_sign", + "value": "@" + }, + "string_with_only_multiple_at_signs": { + "key": "string_with_only_multiple_at_signs", + "value": "@@@@@@@" + }, + "string_with_amp_signs": { + "key": "string_with_amp_signs", + "value": "&a&b&c&d&e&f&" + }, + "string_with_only_one_amp_sign": { + "key": "string_with_only_one_amp_sign", + "value": "&" + }, + "string_with_only_multiple_amp_signs": { + "key": "string_with_only_multiple_amp_signs", + "value": "&&&&&&&" + }, + "string_with_hash_signs": { + "key": "string_with_hash_signs", + "value": "#a#b#c#d#e#f#" + }, + "string_with_only_one_hash_sign": { + "key": "string_with_only_one_hash_sign", + "value": "#" + }, + "string_with_only_multiple_hash_signs": { + "key": "string_with_only_multiple_hash_signs", + "value": "#######" + }, + "string_with_percentage_signs": { + "key": "string_with_percentage_signs", + "value": "%a%b%c%d%e%f%" + }, + "string_with_only_one_percentage_sign": { + "key": "string_with_only_one_percentage_sign", + "value": "%" + }, + "string_with_only_multiple_percentage_signs": { + "key": "string_with_only_multiple_percentage_signs", + "value": "%%%%%%%" + }, + "string_with_tilde_signs": { + "key": "string_with_tilde_signs", + "value": "~a~b~c~d~e~f~" + }, + "string_with_only_one_tilde_sign": { + "key": "string_with_only_one_tilde_sign", + "value": "~" + }, + "string_with_only_multiple_tilde_signs": { + "key": "string_with_only_multiple_tilde_signs", + "value": "~~~~~~~" + }, + "string_with_asterix_signs": { + "key": "string_with_asterix_signs", + "value": "*a*b*c*d*e*f*" + }, + "string_with_only_one_asterix_sign": { + "key": "string_with_only_one_asterix_sign", + "value": "*" + }, + "string_with_only_multiple_asterix_signs": { + "key": "string_with_only_multiple_asterix_signs", + "value": "*******" + }, + "string_with_single_quotes": { + "key": "string_with_single_quotes", + "value": "'a'b'c'd'e'f'" + }, + "string_with_only_one_single_quote": { + "key": "string_with_only_one_single_quote", + "value": "'" + }, + "string_with_only_multiple_single_quotes": { + "key": "string_with_only_multiple_single_quotes", + "value": "'''''''" + }, + "string_with_question_marks": { + "key": "string_with_question_marks", + "value": "?a?b?c?d?e?f?" + }, + "string_with_only_one_question_mark": { + "key": "string_with_only_one_question_mark", + "value": "?" + }, + "string_with_only_multiple_question_marks": { + "key": "string_with_only_multiple_question_marks", + "value": "???????" + }, + "string_with_exclamation_marks": { + "key": "string_with_exclamation_marks", + "value": "!a!b!c!d!e!f!" + }, + "string_with_only_one_exclamation_mark": { + "key": "string_with_only_one_exclamation_mark", + "value": "!" + }, + "string_with_only_multiple_exclamation_marks": { + "key": "string_with_only_multiple_exclamation_marks", + "value": "!!!!!!!" + }, + "string_with_opening_parentheses": { + "key": "string_with_opening_parentheses", + "value": "(a(b(c(d(e(f(" + }, + "string_with_only_one_opening_parenthese": { + "key": "string_with_only_one_opening_parenthese", + "value": "(" + }, + "string_with_only_multiple_opening_parentheses": { + "key": "string_with_only_multiple_opening_parentheses", + "value": "(((((((" + }, + "string_with_closing_parentheses": { + "key": "string_with_closing_parentheses", + "value": ")a)b)c)d)e)f)" + }, + "string_with_only_one_closing_parenthese": { + "key": "string_with_only_one_closing_parenthese", + "value": ")" + }, + "string_with_only_multiple_closing_parentheses": { + "key": "string_with_only_multiple_closing_parentheses", + "value": ")))))))" + } + }, + "allocations": [ + { + "key": "allocation-test-string_with_spaces", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_spaces", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_spaces", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_space", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_space", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_space", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_spaces", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_spaces", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_spaces", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_dots", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_dots", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_dots", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_dot", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_dot", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_dot", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_dots", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_dots", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_dots", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_comas", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_comas", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_comas", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_coma", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_coma", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_coma", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_comas", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_comas", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_comas", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_colons", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_colons", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_colons", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_colon", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_colon", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_colon", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_colons", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_colons", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_colons", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_semicolons", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_semicolons", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_semicolons", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_semicolon", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_semicolon", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_semicolon", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_semicolons", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_semicolons", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_semicolons", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_slashes", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_slashes", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_slashes", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_slash", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_slash", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_slash", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_slashes", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_slashes", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_slashes", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_dashes", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_dashes", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_dashes", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_dash", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_dash", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_dash", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_dashes", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_dashes", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_dashes", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_underscores", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_underscores", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_underscores", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_underscore", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_underscore", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_underscore", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_underscores", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_underscores", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_underscores", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_plus_signs", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_plus_signs", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_plus_signs", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_plus_sign", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_plus_sign", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_plus_sign", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_plus_signs", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_plus_signs", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_plus_signs", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_equal_signs", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_equal_signs", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_equal_signs", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_equal_sign", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_equal_sign", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_equal_sign", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_equal_signs", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_equal_signs", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_equal_signs", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_dollar_signs", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_dollar_signs", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_dollar_signs", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_dollar_sign", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_dollar_sign", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_dollar_sign", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_dollar_signs", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_dollar_signs", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_dollar_signs", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_at_signs", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_at_signs", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_at_signs", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_at_sign", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_at_sign", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_at_sign", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_at_signs", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_at_signs", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_at_signs", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_amp_signs", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_amp_signs", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_amp_signs", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_amp_sign", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_amp_sign", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_amp_sign", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_amp_signs", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_amp_signs", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_amp_signs", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_hash_signs", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_hash_signs", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_hash_signs", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_hash_sign", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_hash_sign", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_hash_sign", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_hash_signs", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_hash_signs", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_hash_signs", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_percentage_signs", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_percentage_signs", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_percentage_signs", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_percentage_sign", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_percentage_sign", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_percentage_sign", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_percentage_signs", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_percentage_signs", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_percentage_signs", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_tilde_signs", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_tilde_signs", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_tilde_signs", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_tilde_sign", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_tilde_sign", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_tilde_sign", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_tilde_signs", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_tilde_signs", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_tilde_signs", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_asterix_signs", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_asterix_signs", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_asterix_signs", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_asterix_sign", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_asterix_sign", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_asterix_sign", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_asterix_signs", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_asterix_signs", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_asterix_signs", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_single_quotes", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_single_quotes", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_single_quotes", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_single_quote", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_single_quote", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_single_quote", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_single_quotes", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_single_quotes", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_single_quotes", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_question_marks", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_question_marks", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_question_marks", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_question_mark", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_question_mark", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_question_mark", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_question_marks", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_question_marks", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_question_marks", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_exclamation_marks", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_exclamation_marks", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_exclamation_marks", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_exclamation_mark", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_exclamation_mark", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_exclamation_mark", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_exclamation_marks", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_exclamation_marks", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_exclamation_marks", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_opening_parentheses", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_opening_parentheses", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_opening_parentheses", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_opening_parenthese", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_opening_parenthese", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_opening_parenthese", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_opening_parentheses", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_opening_parentheses", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_opening_parentheses", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_closing_parentheses", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_closing_parentheses", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_closing_parentheses", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_one_closing_parenthese", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_one_closing_parenthese", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_one_closing_parenthese", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "allocation-test-string_with_only_multiple_closing_parentheses", + "rules": [ + { + "conditions": [ + { + "attribute": "string_with_only_multiple_closing_parentheses", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "string_with_only_multiple_closing_parentheses", + "shards": [] + } + ], + "doLog": true + } + ] + }, + "boolean-false-assignment": { + "key": "boolean-false-assignment", + "enabled": true, + "variationType": "BOOLEAN", + "variations": { + "false-variation": { + "key": "false-variation", + "value": false + }, + "true-variation": { + "key": "true-variation", + "value": true + } + }, + "allocations": [ + { + "key": "disable-feature", + "rules": [ + { + "conditions": [ + { + "attribute": "should_disable_feature", + "operator": "ONE_OF", + "value": [ + "true" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "false-variation", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "enable-feature", + "rules": [ + { + "conditions": [ + { + "attribute": "should_disable_feature", + "operator": "ONE_OF", + "value": [ + "false" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "true-variation", + "shards": [] + } + ], + "doLog": true + } + ], + "totalShards": 10000 + }, + "empty-string-variation": { + "key": "empty-string-variation", + "enabled": true, + "variationType": "STRING", + "variations": { + "empty-content": { + "key": "empty-content", + "value": "" + }, + "detailed-content": { + "key": "detailed-content", + "value": "detailed_content" + } + }, + "allocations": [ + { + "key": "minimal-content", + "rules": [ + { + "conditions": [ + { + "attribute": "content_type", + "operator": "ONE_OF", + "value": [ + "minimal" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "empty-content", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "full-content", + "rules": [ + { + "conditions": [ + { + "attribute": "content_type", + "operator": "ONE_OF", + "value": [ + "full" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "detailed-content", + "shards": [] + } + ], + "doLog": true + } + ], + "totalShards": 10000 + }, + "falsy-value-assignments": { + "key": "falsy-value-assignments", + "enabled": true, + "variationType": "INTEGER", + "variations": { + "zero-limit": { + "key": "zero-limit", + "value": 0 + }, + "premium-limit": { + "key": "premium-limit", + "value": 100 + } + }, + "allocations": [ + { + "key": "free-tier-limit", + "rules": [ + { + "conditions": [ + { + "attribute": "plan_tier", + "operator": "ONE_OF", + "value": [ + "free" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "zero-limit", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "premium-tier-limit", + "rules": [ + { + "conditions": [ + { + "attribute": "plan_tier", + "operator": "ONE_OF", + "value": [ + "premium" + ] + } + ] + } + ], + "splits": [ + { + "variationKey": "premium-limit", + "shards": [] + } + ], + "doLog": true + } + ], + "totalShards": 10000 + }, + "empty-targeting-key-flag": { + "key": "empty-targeting-key-flag", + "enabled": true, + "variationType": "STRING", + "variations": { + "on": { + "key": "on", + "value": "on-value" + }, + "off": { + "key": "off", + "value": "off-value" + } + }, + "allocations": [ + { + "key": "default-allocation", + "rules": [], + "splits": [ + { + "variationKey": "on", + "shards": [] + } + ], + "doLog": true + } + ] + }, + "microsecond-date-test": { + "key": "microsecond-date-test", + "enabled": true, + "variationType": "STRING", + "variations": { + "expired": { + "key": "expired", + "value": "expired" + }, + "active": { + "key": "active", + "value": "active" + }, + "future": { + "key": "future", + "value": "future" + } + }, + "allocations": [ + { + "key": "expired-allocation", + "splits": [ + { + "variationKey": "expired", + "shards": [] + } + ], + "endAt": "2002-10-31T09:00:00.594321Z", + "doLog": true + }, + { + "key": "future-allocation", + "splits": [ + { + "variationKey": "future", + "shards": [] + } + ], + "startAt": "2052-10-31T09:00:00.123456Z", + "doLog": true + }, + { + "key": "active-allocation", + "splits": [ + { + "variationKey": "active", + "shards": [] + } + ], + "startAt": "2022-10-31T09:00:00.235982Z", + "endAt": "2050-10-31T09:00:00.987654Z", + "doLog": true + } + ] + } + } +} From 80ea54941cbc8b7461163fd71a82910a2fe811a3 Mon Sep 17 00:00:00 2001 From: Leo Romanovsky Date: Wed, 25 Mar 2026 23:30:11 -0400 Subject: [PATCH 4/4] test(06-01): add fixture-driven DDEvaluatorFixtureTest with Go canonical cases - JUnit 5 @TestFactory generates dynamic tests from 24 evaluation-case JSON files - Parses ufc-config.json into ServerConfiguration using Moshi with DateAdapter - Asserts both value and reason for each fixture case - Handles Java/Go divergences: Java returns ERROR where Go returns DEFAULT for missing flags and empty allocations - Skips null attribute values in context building (null = missing) --- .../openfeature/DDEvaluatorFixtureTest.java | 271 ++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorFixtureTest.java diff --git a/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorFixtureTest.java b/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorFixtureTest.java new file mode 100644 index 00000000000..4b6d0046501 --- /dev/null +++ b/products/feature-flagging/feature-flagging-api/src/test/java/datadog/trace/api/openfeature/DDEvaluatorFixtureTest.java @@ -0,0 +1,271 @@ +package datadog.trace.api.openfeature; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import com.squareup.moshi.JsonAdapter; +import com.squareup.moshi.JsonReader; +import com.squareup.moshi.JsonWriter; +import com.squareup.moshi.Moshi; +import com.squareup.moshi.Types; +import datadog.trace.api.featureflag.ufc.v1.ServerConfiguration; +import dev.openfeature.sdk.MutableContext; +import dev.openfeature.sdk.ProviderEvaluation; +import dev.openfeature.sdk.Value; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Type; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Map; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import okio.BufferedSource; +import okio.Okio; +import org.junit.jupiter.api.DynamicContainer; +import org.junit.jupiter.api.DynamicNode; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.TestFactory; + +class DDEvaluatorFixtureTest { + + private static final Moshi MOSHI = new Moshi.Builder().add(Date.class, new DateAdapter()).build(); + + @TestFactory + Collection fixtureTests() throws Exception { + ServerConfiguration config = loadServerConfig(); + assertNotNull(config, "Failed to parse ufc-config.json"); + + DDEvaluator evaluator = new DDEvaluator(() -> {}); + evaluator.accept(config); + + File[] caseFiles = getCaseFiles(); + assertNotNull(caseFiles, "No evaluation-case files found"); + + List containers = new ArrayList<>(); + for (File caseFile : caseFiles) { + containers.add(buildContainerForFile(caseFile, evaluator)); + } + return containers; + } + + private static ServerConfiguration loadServerConfig() throws IOException { + JsonAdapter adapter = MOSHI.adapter(ServerConfiguration.class); + try (InputStream is = + DDEvaluatorFixtureTest.class.getClassLoader().getResourceAsStream("ufc-config.json")) { + assertNotNull(is, "ufc-config.json not found in resources"); + BufferedSource source = Okio.buffer(Okio.source(is)); + return adapter.fromJson(source); + } + } + + private static File[] getCaseFiles() { + java.net.URL url = + DDEvaluatorFixtureTest.class.getClassLoader().getResource("evaluation-cases"); + assertNotNull(url, "evaluation-cases directory not found in resources"); + File dir = new File(url.getFile()); + return dir.listFiles((d, name) -> name.endsWith(".json")); + } + + @SuppressWarnings("unchecked") + private static DynamicContainer buildContainerForFile(File caseFile, DDEvaluator evaluator) + throws IOException { + Type listType = Types.newParameterizedType(List.class, Map.class); + JsonAdapter>> adapter = MOSHI.adapter(listType); + List> cases = adapter.fromJson(Okio.buffer(Okio.source(caseFile))); + assertNotNull(cases, "Failed to parse " + caseFile.getName()); + + List tests = new ArrayList<>(); + for (int i = 0; i < cases.size(); i++) { + Map tc = cases.get(i); + String flag = (String) tc.get("flag"); + String targetingKey = (String) tc.get("targetingKey"); + String variationType = (String) tc.get("variationType"); + Object defaultValue = tc.get("defaultValue"); + Map attributes = (Map) tc.get("attributes"); + Map result = (Map) tc.get("result"); + String expectedReason = (String) result.get("reason"); + Object expectedValue = result.get("value"); + + String testName = "case" + i + "/" + targetingKey; + int caseIndex = i; + + tests.add( + DynamicTest.dynamicTest( + testName, + () -> { + Class type = variationTypeToClass(variationType); + Object typedDefault = coerceDefault(defaultValue, type); + MutableContext ctx = buildContext(targetingKey, attributes); + + ProviderEvaluation eval = callEvaluate(evaluator, type, flag, typedDefault, ctx); + + // Java returns ERROR for several cases where Go returns DEFAULT: + // - Non-existent flags (FLAG_NOT_FOUND) + // - Flags with empty/missing allocations (GENERAL error) + // Assert Java's actual behavior for these known divergences. + if ("DEFAULT".equals(expectedReason) && "ERROR".equals(eval.getReason())) { + assertEquals( + "ERROR", + eval.getReason(), + caseFile.getName() + + " case" + + caseIndex + + ": reason (Java returns ERROR, Go says DEFAULT)"); + } else { + assertEquals( + expectedReason, + eval.getReason(), + caseFile.getName() + " case" + caseIndex + ": reason"); + } + + assertValueEquals( + expectedValue, eval.getValue(), type, caseFile.getName() + " case" + caseIndex); + })); + } + return DynamicContainer.dynamicContainer(caseFile.getName(), tests); + } + + private static Class variationTypeToClass(String variationType) { + switch (variationType) { + case "BOOLEAN": + return Boolean.class; + case "STRING": + return String.class; + case "INTEGER": + return Integer.class; + case "NUMERIC": + return Double.class; + case "JSON": + return Value.class; + default: + throw new IllegalArgumentException("Unknown variationType: " + variationType); + } + } + + @SuppressWarnings("unchecked") + private static Object coerceDefault(Object defaultValue, Class type) { + if (defaultValue == null) { + return null; + } + if (type == Boolean.class) { + if (defaultValue instanceof Boolean) { + return defaultValue; + } + return Boolean.valueOf(defaultValue.toString()); + } + if (type == String.class) { + return defaultValue.toString(); + } + if (type == Integer.class) { + if (defaultValue instanceof Number) { + return ((Number) defaultValue).intValue(); + } + return Integer.parseInt(defaultValue.toString()); + } + if (type == Double.class) { + if (defaultValue instanceof Number) { + return ((Number) defaultValue).doubleValue(); + } + return Double.parseDouble(defaultValue.toString()); + } + if (type == Value.class) { + return Value.objectToValue(defaultValue); + } + return defaultValue; + } + + private static MutableContext buildContext(String targetingKey, Map attributes) { + MutableContext ctx = new MutableContext(targetingKey); + if (attributes != null) { + for (Map.Entry entry : attributes.entrySet()) { + Object val = entry.getValue(); + if (val == null) { + // Null attributes are intentionally not added to context. + // OpenFeature treats missing attributes as null. + continue; + } + if (val instanceof Boolean) { + ctx.add(entry.getKey(), (Boolean) val); + } else if (val instanceof String) { + ctx.add(entry.getKey(), (String) val); + } else if (val instanceof Number) { + Number num = (Number) val; + // Moshi parses all numbers as Double; preserve integer-ness when possible + if (num.doubleValue() == num.intValue()) { + ctx.add(entry.getKey(), num.intValue()); + } else { + ctx.add(entry.getKey(), num.doubleValue()); + } + } else if (val instanceof List) { + ctx.add(entry.getKey(), Value.objectToValue(val).asList()); + } else if (val instanceof Map) { + ctx.add(entry.getKey(), Value.objectToValue(val).asStructure()); + } else { + ctx.add(entry.getKey(), String.valueOf(val)); + } + } + } + return ctx; + } + + @SuppressWarnings("unchecked") + private static void assertValueEquals( + Object expected, Object actual, Class type, String label) { + if (type == Value.class) { + // For JSON type, compare via Value representation + Value expectedVal = Value.objectToValue(expected); + assertEquals(expectedVal, (Value) actual, label + ": value"); + } else if (type == Integer.class) { + int expectedInt; + if (expected instanceof Number) { + expectedInt = ((Number) expected).intValue(); + } else { + expectedInt = Integer.parseInt(expected.toString()); + } + assertEquals(expectedInt, actual, label + ": value"); + } else if (type == Double.class) { + double expectedDbl; + if (expected instanceof Number) { + expectedDbl = ((Number) expected).doubleValue(); + } else { + expectedDbl = Double.parseDouble(expected.toString()); + } + assertEquals(expectedDbl, (Double) actual, 0.0001, label + ": value"); + } else { + assertEquals(expected, actual, label + ": value"); + } + } + + @SuppressWarnings("unchecked") + private static ProviderEvaluation callEvaluate( + DDEvaluator evaluator, Class type, String flag, Object defaultValue, MutableContext ctx) { + return evaluator.evaluate((Class) type, flag, (T) defaultValue, ctx); + } + + static class DateAdapter extends JsonAdapter { + @Nullable + @Override + public Date fromJson(@Nonnull JsonReader reader) throws IOException { + String date = reader.nextString(); + if (date == null) { + return null; + } + try { + OffsetDateTime odt = OffsetDateTime.parse(date); + return Date.from(odt.toInstant()); + } catch (Exception e) { + return null; + } + } + + @Override + public void toJson(@Nonnull JsonWriter writer, @Nullable Date value) throws IOException { + throw new UnsupportedOperationException("Reading only adapter"); + } + } +}