diff --git a/.github/actions/create-signed-pull-request/action.yml b/.github/actions/create-signed-pull-request/action.yml index 48e9690fc6cd..afad240599e1 100644 --- a/.github/actions/create-signed-pull-request/action.yml +++ b/.github/actions/create-signed-pull-request/action.yml @@ -30,6 +30,10 @@ inputs: reviewers: description: 'Comma-separated reviewers to request. GitHub usernames, not teams.' required: false + draft: + description: 'Whether to create the pull request as a draft.' + required: false + default: 'false' outputs: pull-request-number: @@ -55,4 +59,5 @@ runs: body: ${{ inputs.body }} labels: ${{ inputs.labels }} reviewers: ${{ inputs.reviewers }} + draft: ${{ inputs.draft }} delete-branch: true diff --git a/.github/chainguard/self.update_ffe_fixtures.create-pr.sts.yaml b/.github/chainguard/self.update_ffe_fixtures.create-pr.sts.yaml new file mode 100644 index 000000000000..66d33e2bf75a --- /dev/null +++ b/.github/chainguard/self.update_ffe_fixtures.create-pr.sts.yaml @@ -0,0 +1,13 @@ +issuer: https://token.actions.githubusercontent.com + +subject_pattern: repo:DataDog/dd-trace-dotnet:.* + +claim_pattern: + event_name: (schedule|workflow_dispatch) + ref: refs/heads/master + ref_protected: "true" + job_workflow_ref: DataDog/dd-trace-dotnet/\.github/workflows/update_ffe_fixtures\.yml@refs/heads/master + +permissions: + contents: write + pull_requests: write diff --git a/.github/workflows/update_ffe_fixtures.yml b/.github/workflows/update_ffe_fixtures.yml new file mode 100644 index 000000000000..eb08fbc42293 --- /dev/null +++ b/.github/workflows/update_ffe_fixtures.yml @@ -0,0 +1,77 @@ +name: Update FFE fixtures + +on: + schedule: + - cron: "0 0 * * 0" # Every Sunday at midnight UTC + workflow_dispatch: + inputs: + fixture_ref: + description: Branch, tag, or commit from DataDog/ffe-system-test-data + required: true + default: main + type: string + +concurrency: + group: update-ffe-fixtures + cancel-in-progress: false + +jobs: + update_ffe_fixtures: + runs-on: ubuntu-latest + permissions: + id-token: write + + steps: + - name: Get dd-octo-sts token + uses: DataDog/dd-octo-sts-action@96a25462dbcb10ebf0bfd6e2ccc917d2ab235b9a # v1.0.4 + id: octo-sts + with: + scope: DataDog/dd-trace-dotnet + policy: self.update_ffe_fixtures.create-pr + + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Update fixture snapshot + id: fixtures + env: + FFE_FIXTURE_REF: ${{ inputs.fixture_ref || 'main' }} + run: ./tracer/build.sh UpdateFfeFixtures --FfeFixtureRef "$FFE_FIXTURE_REF" + + - name: Create Pull Request + if: steps.fixtures.outputs.changed == 'true' + uses: ./.github/actions/create-signed-pull-request + with: + token: ${{ steps.octo-sts.outputs.token }} + branch: bot/ffe-fixtures-update + commit-message: "test(ffe): update canonical fixtures" + base: master + title: "test(ffe): update canonical fixtures" + draft: true + labels: "area:tests,feature_flags" + body: | + ## Summary of changes + + Updates the FFE tests to commit ${{ steps.fixtures.outputs.source_commit }}. + + ## Reason for change + + Keep dd-trace-dotnet synchronized with the canonical FFE evaluator fixtures. New fixtures may intentionally make unit tests fail when they expose evaluator bugs that must be addressed before this update is merged. + + Canonical source: https://github.com/DataDog/ffe-system-test-data + Source commit: ${{ steps.fixtures.outputs.source_commit }} + + ## Implementation details + + - Refresh the checked-in FFE fixture snapshot from the canonical repository. + - Load ${{ steps.fixtures.outputs.fixture_count }} canonical JSON fixture cases. + + ## Test coverage + + The existing FFE unit tests run against the refreshed canonical fixtures. + + ## Other details + + Address evaluator failures in this update PR before merging it. diff --git a/tracer/build/_build/Build.FfeFixtures.cs b/tracer/build/_build/Build.FfeFixtures.cs new file mode 100644 index 000000000000..47c2e64f3c44 --- /dev/null +++ b/tracer/build/_build/Build.FfeFixtures.cs @@ -0,0 +1,239 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using Nuke.Common; +using Nuke.Common.IO; +using Nuke.Common.Tooling; +using static Nuke.Common.IO.FileSystemTasks; +using Logger = Serilog.Log; + +partial class Build +{ + private static readonly HashSet FfeFixtureCopyDisallowList = new(StringComparer.Ordinal) + { + ".git", + ".github", + ".gitignore", + "ci", + "CONTRIBUTING.md", + "LICENSE", + "LICENSE-3rdparty.csv", + "NOTICE", + "README.md", + "SOURCE.md", + }; + + [Parameter("Branch, tag, or commit to copy from DataDog/ffe-system-test-data")] + readonly string FfeFixtureRef = "main"; + + Target UpdateFfeFixtures => _ => _ + .Description("Updates the checked-in FFE fixtures from DataDog/ffe-system-test-data") + .Executes(() => + { + ValidateFixtureRef(FfeFixtureRef); + + var destination = RootDirectory / "tracer" / "test" / "Datadog.Trace.Tests" / "FeatureFlags" / "ffe-system-test-data"; + var workingDirectory = TemporaryDirectory / $"ffe-system-test-data-{Guid.NewGuid():N}"; + var source = workingDirectory / "source"; + var snapshot = workingDirectory / "snapshot"; + var emptyGitConfig = workingDirectory / "empty-git-config"; + + try + { + EnsureExistingDirectory(source); + EnsureExistingDirectory(snapshot); + File.WriteAllText(emptyGitConfig, string.Empty); + + var gitEnvironment = new Dictionary + { + ["GIT_CONFIG_NOSYSTEM"] = "1", + ["GIT_CONFIG_GLOBAL"] = emptyGitConfig, + }; + + RunGit(source, "init --quiet", gitEnvironment); + RunGit(source, "remote add origin https://github.com/DataDog/ffe-system-test-data.git", gitEnvironment); + RunGit(source, $"fetch --quiet --depth 1 origin {FfeFixtureRef}", gitEnvironment); + RunGit(source, "checkout --quiet --detach FETCH_HEAD", gitEnvironment); + var sourceCommit = RunGit(source, "rev-parse HEAD", gitEnvironment); + + CopyFixtureSnapshot(source, snapshot); + var fixtureCount = ValidateFixtureSnapshot(snapshot); + var changed = !HaveSameContents(snapshot, destination); + + if (changed) + { + File.WriteAllText( + snapshot / "SOURCE.md", + $""" +# FFE Fixture Snapshot + +These files are copied from the canonical FFE fixture repository. + +Canonical source: https://github.com/DataDog/ffe-system-test-data +Source commit: {sourceCommit} + +Do not edit these fixtures directly in dd-trace-dotnet. Add or update shared FFE behavior in ffe-system-test-data first, then refresh this snapshot. + +The weekly update workflow runs `./tracer/build.sh UpdateFfeFixtures` and opens a draft test PR only when the allowed fixture contents change. +"""); + + EnsureCleanDirectory(destination); + CopyDirectory(snapshot, destination); + } + + Logger.Information("Checked FFE fixtures from DataDog/ffe-system-test-data@{SourceCommit}", sourceCommit); + Logger.Information("Loaded {FixtureCount} JSON fixture cases", fixtureCount); + Logger.Information("Fixture snapshot changed: {Changed}", changed); + + var githubOutput = Environment.GetEnvironmentVariable("GITHUB_OUTPUT"); + if (!string.IsNullOrWhiteSpace(githubOutput)) + { + File.AppendAllLines( + githubOutput, + new[] + { + $"source_commit={sourceCommit}", + $"fixture_count={fixtureCount}", + $"changed={changed.ToString().ToLowerInvariant()}", + }); + } + } + finally + { + DeleteDirectory(workingDirectory); + } + }); + + private static void ValidateFixtureRef(string fixtureRef) + { + if (string.IsNullOrWhiteSpace(fixtureRef) + || fixtureRef.StartsWith("-", StringComparison.Ordinal) + || fixtureRef.Contains("..", StringComparison.Ordinal) + || fixtureRef.Any(character => !(char.IsLetterOrDigit(character) || character is '.' or '_' or '/' or '-'))) + { + throw new ArgumentException($"Invalid FFE fixture ref: {fixtureRef}", nameof(fixtureRef)); + } + } + + private static string RunGit(AbsolutePath workingDirectory, string arguments, IReadOnlyDictionary environment) + { + var process = ProcessTasks.StartProcess( + "git", + arguments, + workingDirectory, + environmentVariables: environment, + logOutput: false); + process.AssertZeroExitCode(); + return string.Join(Environment.NewLine, process.Output.Select(line => line.Text)).Trim(); + } + + private static void CopyFixtureSnapshot(AbsolutePath source, AbsolutePath snapshot) + { + foreach (var entry in new DirectoryInfo(source).EnumerateFileSystemInfos()) + { + if (FfeFixtureCopyDisallowList.Contains(entry.Name)) + { + continue; + } + + CopyEntry(entry, Path.Combine(snapshot, entry.Name)); + } + } + + private static void CopyEntry(FileSystemInfo source, string destination) + { + if ((source.Attributes & FileAttributes.ReparsePoint) != 0) + { + throw new InvalidOperationException($"Refusing to copy symbolic link from FFE fixture repository: {source.FullName}"); + } + + if (source is FileInfo file) + { + Directory.CreateDirectory(Path.GetDirectoryName(destination)!); + file.CopyTo(destination, overwrite: true); + return; + } + + Directory.CreateDirectory(destination); + foreach (var child in ((DirectoryInfo)source).EnumerateFileSystemInfos()) + { + CopyEntry(child, Path.Combine(destination, child.Name)); + } + } + + private static int ValidateFixtureSnapshot(AbsolutePath snapshot) + { + var configPath = snapshot / "ufc-config.json"; + var casesDirectory = snapshot / "evaluation-cases"; + if (!File.Exists(configPath) || !Directory.Exists(casesDirectory)) + { + throw new InvalidOperationException("FFE fixture repository does not contain the expected fixture layout"); + } + + using (var config = JsonDocument.Parse(File.ReadAllText(configPath))) + { + } + + var caseFiles = Directory.GetFiles(casesDirectory, "*.json").OrderBy(path => path, StringComparer.Ordinal).ToArray(); + if (caseFiles.Length == 0) + { + throw new InvalidOperationException("No FFE JSON fixture files found"); + } + + var fixtureCount = 0; + foreach (var caseFile in caseFiles) + { + using var cases = JsonDocument.Parse(File.ReadAllText(caseFile)); + if (cases.RootElement.ValueKind != JsonValueKind.Array) + { + throw new InvalidOperationException($"{caseFile} must contain a JSON array of test cases"); + } + + fixtureCount += cases.RootElement.GetArrayLength(); + } + + if (fixtureCount == 0) + { + throw new InvalidOperationException("No FFE fixture test cases found"); + } + + return fixtureCount; + } + + private static bool HaveSameContents(AbsolutePath snapshot, AbsolutePath destination) + { + if (!Directory.Exists(destination)) + { + return false; + } + + var snapshotFiles = GetRelativeFiles(snapshot); + var destinationFiles = GetRelativeFiles(destination, "SOURCE.md"); + if (!snapshotFiles.SequenceEqual(destinationFiles, StringComparer.Ordinal)) + { + return false; + } + + return snapshotFiles.All(relativePath => + File.ReadAllBytes(snapshot / relativePath).AsSpan().SequenceEqual(File.ReadAllBytes(destination / relativePath))); + } + + private static string[] GetRelativeFiles(AbsolutePath directory, params string[] excludedFiles) + { + return Directory.GetFiles(directory, "*", SearchOption.AllDirectories) + .Select(path => Path.GetRelativePath(directory, path)) + .Where(path => !excludedFiles.Contains(path, StringComparer.Ordinal)) + .OrderBy(path => path, StringComparer.Ordinal) + .ToArray(); + } + + private static void CopyDirectory(AbsolutePath source, AbsolutePath destination) + { + foreach (var entry in new DirectoryInfo(source).EnumerateFileSystemInfos()) + { + CopyEntry(entry, Path.Combine(destination, entry.Name)); + } + } +} diff --git a/tracer/src/Datadog.Trace/FeatureFlags/FeatureFlagsEvaluator.cs b/tracer/src/Datadog.Trace/FeatureFlags/FeatureFlagsEvaluator.cs index 073f50ff6c87..40cfc1594afd 100644 --- a/tracer/src/Datadog.Trace/FeatureFlags/FeatureFlagsEvaluator.cs +++ b/tracer/src/Datadog.Trace/FeatureFlags/FeatureFlagsEvaluator.cs @@ -70,7 +70,9 @@ public Evaluation Evaluate(string flagKey, ValueType resultType, object? default }); } - if (config.Flags is null || !config.Flags.TryGetValue(flagKey, out var flag) || flag is null) + Flag? flag = null; + var lookupResult = config.Flags?.Find(flagKey, out flag) ?? FlagLookupResult.NotFound; + if (lookupResult == FlagLookupResult.NotFound) { return new Evaluation( flagKey, @@ -83,6 +85,19 @@ public Evaluation Evaluate(string flagKey, ValueType resultType, object? default }); } + if (lookupResult == FlagLookupResult.Invalid || flag is null) + { + return new Evaluation( + flagKey, + defaultValue, + EvaluationReason.Error, + error: "PARSE_ERROR", + metadata: new Dictionary + { + ["errorCode"] = "PARSE_ERROR" + }); + } + if (flag.Enabled != true) { return new Evaluation( @@ -158,12 +173,18 @@ public Evaluation Evaluate(string flagKey, ValueType resultType, object? default if (allShardsMatch) { // Determine reason based on how the flag was resolved. - // Per the FFE spec, SPLIT takes precedence over TARGETING_MATCH: - // - Split: Resolved via percentage split (shards present) - // - TargetingMatch: Allocation had targeting rules that matched (no shards) + // - TargetingMatch: Allocation had targeting rules that matched + // - Default: A temporal allocation with one unsharded split matched + // - Split: Resolved via percentage split without targeting rules // - Static: No rules, no shards - simple static value - var reason = hadShards ? EvaluationReason.Split - : hadRules ? EvaluationReason.TargetingMatch + var isTemporalDefault = !hadRules && + !hadShards && + allocation.Splits.Count == 1 && + (!StringUtil.IsNullOrEmpty(allocation.StartAt) || + !StringUtil.IsNullOrEmpty(allocation.EndAt)); + var reason = hadRules ? EvaluationReason.TargetingMatch + : isTemporalDefault ? EvaluationReason.Default + : hadShards ? EvaluationReason.Split : EvaluationReason.Static; return ResolveVariant(flagKey, resultType, defaultValue, flag, split, allocation, reason, now, context); @@ -302,6 +323,18 @@ private static bool EvaluateCondition(ConditionConfiguration condition, Evaluati return CompareNumber(attributeValue, condition.Value, (a, b) => a <= b); case ConditionOperator.LT: return CompareNumber(attributeValue, condition.Value, (a, b) => a < b); + case ConditionOperator.SEMVER_EQ: + return CompareSemanticVersion(attributeValue, condition.Value, result => result == 0); + case ConditionOperator.SEMVER_NEQ: + return CompareSemanticVersion(attributeValue, condition.Value, result => result != 0); + case ConditionOperator.SEMVER_LT: + return CompareSemanticVersion(attributeValue, condition.Value, result => result < 0); + case ConditionOperator.SEMVER_LTE: + return CompareSemanticVersion(attributeValue, condition.Value, result => result <= 0); + case ConditionOperator.SEMVER_GT: + return CompareSemanticVersion(attributeValue, condition.Value, result => result > 0); + case ConditionOperator.SEMVER_GTE: + return CompareSemanticVersion(attributeValue, condition.Value, result => result >= 0); default: throw new FormatException($"Unknown condition operator {condition.Operator.ToString()}"); } @@ -371,6 +404,15 @@ private static bool CompareNumber(object attributeValue, object? conditionValue, return comparator(a, b); } + private static bool CompareSemanticVersion(object attributeValue, object? conditionValue, Func comparator) + { + return attributeValue is string attributeText + && conditionValue is string conditionText + && SemanticVersion.TryParse(attributeText, out var attributeVersion) + && SemanticVersion.TryParse(conditionText, out var conditionVersion) + && comparator(attributeVersion.CompareTo(conditionVersion)); + } + private static bool MatchesShard(Shard shard, string? targetingKey) { if (shard.Ranges is null) @@ -434,12 +476,7 @@ internal static int GetShard(string salt, string? targetingKey, int totalShards) // Special case "id": if not present, use targeting key if (name == "id" && !context.Attributes.ContainsKey(name)) { - if (StringUtil.IsNullOrEmpty(context.TargetingKey)) - { - throw new MissingTargetingKeyException(); - } - - return context.TargetingKey; + return StringUtil.IsNullOrEmpty(context.TargetingKey) ? null : context.TargetingKey; } return context.GetAttribute(name); diff --git a/tracer/src/Datadog.Trace/FeatureFlags/Rcm/Model/ConditionConfiguration.cs b/tracer/src/Datadog.Trace/FeatureFlags/Rcm/Model/ConditionConfiguration.cs index f62084c914f3..dab28af05496 100644 --- a/tracer/src/Datadog.Trace/FeatureFlags/Rcm/Model/ConditionConfiguration.cs +++ b/tracer/src/Datadog.Trace/FeatureFlags/Rcm/Model/ConditionConfiguration.cs @@ -32,6 +32,13 @@ internal bool MatchesRegex(object attributeValue) throw new FormatException("Condition value can not be null nor empty"); } + if (pattern.StartsWith("(?u)", StringComparison.Ordinal)) + { + pattern = pattern.Substring(4); + } + + pattern = pattern.Replace("[:alnum:]", @"\p{L}\p{N}"); + try { _regex = new Regex(pattern, RegexOptions.Compiled); diff --git a/tracer/src/Datadog.Trace/FeatureFlags/Rcm/Model/ConditionOperator.cs b/tracer/src/Datadog.Trace/FeatureFlags/Rcm/Model/ConditionOperator.cs index c2a0b6fb3cb3..fdc33df2b62a 100644 --- a/tracer/src/Datadog.Trace/FeatureFlags/Rcm/Model/ConditionOperator.cs +++ b/tracer/src/Datadog.Trace/FeatureFlags/Rcm/Model/ConditionOperator.cs @@ -21,5 +21,11 @@ internal enum ConditionOperator NOT_MATCHES, ONE_OF, NOT_ONE_OF, - IS_NULL + IS_NULL, + SEMVER_EQ, + SEMVER_NEQ, + SEMVER_LT, + SEMVER_LTE, + SEMVER_GT, + SEMVER_GTE } diff --git a/tracer/src/Datadog.Trace/FeatureFlags/Rcm/Model/FlagCollection.cs b/tracer/src/Datadog.Trace/FeatureFlags/Rcm/Model/FlagCollection.cs new file mode 100644 index 000000000000..96d2be8bf47c --- /dev/null +++ b/tracer/src/Datadog.Trace/FeatureFlags/Rcm/Model/FlagCollection.cs @@ -0,0 +1,81 @@ +// +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc. +// + +#nullable enable + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Datadog.Trace.FeatureFlags.Rcm.Model; + +internal enum FlagLookupResult +{ + Found, + Invalid, + NotFound, +} + +internal sealed class FlagCollection : IEnumerable> +{ + private readonly Dictionary _validFlags = new(); + private readonly HashSet _invalidFlagKeys = new(); + + public int Count => _validFlags.Count + _invalidFlagKeys.Count; + + internal IEnumerable> ValidFlags => _validFlags; + + internal IEnumerable InvalidFlagKeys => _invalidFlagKeys; + + public Flag this[string key] + { + get => _validFlags[key]; + set => Add(key, value); + } + + public void Add(string key, Flag flag) + { + if (flag is null) + { + throw new ArgumentNullException(nameof(flag)); + } + + _invalidFlagKeys.Remove(key); + _validFlags[key] = flag; + } + + public IEnumerator> GetEnumerator() => _validFlags.GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + internal FlagLookupResult Find(string key, out Flag? flag) + { + if (_validFlags.TryGetValue(key, out flag)) + { + return FlagLookupResult.Found; + } + + return _invalidFlagKeys.Contains(key) ? FlagLookupResult.Invalid : FlagLookupResult.NotFound; + } + + internal void MarkInvalid(string key) + { + _validFlags.Remove(key); + _invalidFlagKeys.Add(key); + } + + internal void Merge(FlagCollection other) + { + foreach (var pair in other.ValidFlags) + { + Add(pair.Key, pair.Value); + } + + foreach (var key in other.InvalidFlagKeys) + { + MarkInvalid(key); + } + } +} diff --git a/tracer/src/Datadog.Trace/FeatureFlags/Rcm/Model/FlagCollectionJsonConverter.cs b/tracer/src/Datadog.Trace/FeatureFlags/Rcm/Model/FlagCollectionJsonConverter.cs new file mode 100644 index 000000000000..87a4a8937986 --- /dev/null +++ b/tracer/src/Datadog.Trace/FeatureFlags/Rcm/Model/FlagCollectionJsonConverter.cs @@ -0,0 +1,157 @@ +// +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc. +// + +#nullable enable + +using System; +using Datadog.Trace.Vendors.Newtonsoft.Json; +using Datadog.Trace.Vendors.Newtonsoft.Json.Linq; + +namespace Datadog.Trace.FeatureFlags.Rcm.Model; + +internal sealed class FlagCollectionJsonConverter : JsonConverter +{ + public override FlagCollection? ReadJson( + JsonReader reader, + Type objectType, + FlagCollection? existingValue, + bool hasExistingValue, + JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) + { + return null; + } + + var result = existingValue ?? new FlagCollection(); + var flags = JObject.Load(reader); + foreach (var property in flags.Properties()) + { + try + { + var flag = property.Value.ToObject(serializer); + if (flag is not null && IsValid(flag)) + { + result.Add(property.Name, flag); + } + else + { + result.MarkInvalid(property.Name); + } + } + catch (JsonException) + { + result.MarkInvalid(property.Name); + } + } + + return result; + } + + public override void WriteJson(JsonWriter writer, FlagCollection? value, JsonSerializer serializer) + { + if (value is null) + { + writer.WriteNull(); + return; + } + + writer.WriteStartObject(); + foreach (var pair in value.ValidFlags) + { + writer.WritePropertyName(pair.Key); + serializer.Serialize(writer, pair.Value); + } + + foreach (var key in value.InvalidFlagKeys) + { + writer.WritePropertyName(key); + writer.WriteNull(); + } + + writer.WriteEndObject(); + } + + private static bool IsValid(Flag flag) + { + if (flag.Allocations is null) + { + return true; + } + + foreach (var allocation in flag.Allocations) + { + if (allocation?.Splits is null) + { + return false; + } + + if (allocation.Rules is not null) + { + foreach (var rule in allocation.Rules) + { + if (rule?.Conditions is null) + { + continue; + } + + foreach (var condition in rule.Conditions) + { + if (condition is null || !HasValidOperand(condition)) + { + return false; + } + } + } + } + + foreach (var split in allocation.Splits) + { + if (split?.Shards is null) + { + return false; + } + + foreach (var shard in split.Shards) + { + if (shard is null || shard.TotalShards <= 0 || shard.Ranges is null) + { + return false; + } + + foreach (var range in shard.Ranges) + { + if (range is null || range.Start < 0 || range.End < 0) + { + return false; + } + } + } + } + } + + return true; + } + + private static bool HasValidOperand(ConditionConfiguration condition) + { + if (condition.Operator is ConditionOperator.ONE_OF or ConditionOperator.NOT_ONE_OF) + { + return condition.Value is JArray; + } + + if (condition.Operator is ConditionOperator.SEMVER_EQ + or ConditionOperator.SEMVER_NEQ + or ConditionOperator.SEMVER_LT + or ConditionOperator.SEMVER_LTE + or ConditionOperator.SEMVER_GT + or ConditionOperator.SEMVER_GTE) + { + return condition.Value is string value && SemanticVersion.TryParse(value, out _); + } + + return true; + } +} diff --git a/tracer/src/Datadog.Trace/FeatureFlags/Rcm/Model/ServerConfiguration.cs b/tracer/src/Datadog.Trace/FeatureFlags/Rcm/Model/ServerConfiguration.cs index 937af3519e97..897a1574e80d 100644 --- a/tracer/src/Datadog.Trace/FeatureFlags/Rcm/Model/ServerConfiguration.cs +++ b/tracer/src/Datadog.Trace/FeatureFlags/Rcm/Model/ServerConfiguration.cs @@ -6,7 +6,7 @@ #nullable enable using System; -using System.Collections.Generic; +using Datadog.Trace.Vendors.Newtonsoft.Json; namespace Datadog.Trace.FeatureFlags.Rcm.Model; @@ -18,7 +18,8 @@ internal sealed class ServerConfiguration public Environment? Environment { get; set; } - public Dictionary? Flags { get; set; } + [JsonConverter(typeof(FlagCollectionJsonConverter))] + public FlagCollection? Flags { get; set; } internal void Merge(ServerConfiguration other) { @@ -39,15 +40,12 @@ internal void Merge(ServerConfiguration other) if (Flags is null) { - Flags = new Dictionary(); + Flags = new FlagCollection(); } if (other.Flags is not null) { - foreach (var pair in other.Flags) - { - Flags[pair.Key] = pair.Value; - } + Flags.Merge(other.Flags); } } } diff --git a/tracer/src/Datadog.Trace/FeatureFlags/SemanticVersion.cs b/tracer/src/Datadog.Trace/FeatureFlags/SemanticVersion.cs new file mode 100644 index 000000000000..e44deec8b7e4 --- /dev/null +++ b/tracer/src/Datadog.Trace/FeatureFlags/SemanticVersion.cs @@ -0,0 +1,170 @@ +// +// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License. +// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc. +// + +#nullable enable + +using System; + +namespace Datadog.Trace.FeatureFlags; + +internal readonly struct SemanticVersion : IComparable +{ + private readonly string _major; + private readonly string _minor; + private readonly string _patch; + private readonly string[] _prerelease; + + private SemanticVersion(string major, string minor, string patch, string[] prerelease) + { + _major = major; + _minor = minor; + _patch = patch; + _prerelease = prerelease; + } + + public int CompareTo(SemanticVersion other) + { + var result = CompareNumericIdentifier(_major, other._major); + if (result != 0) + { + return result; + } + + result = CompareNumericIdentifier(_minor, other._minor); + if (result != 0) + { + return result; + } + + result = CompareNumericIdentifier(_patch, other._patch); + if (result != 0) + { + return result; + } + + if (_prerelease.Length == 0 || other._prerelease.Length == 0) + { + return other._prerelease.Length.CompareTo(_prerelease.Length); + } + + var count = Math.Min(_prerelease.Length, other._prerelease.Length); + for (var i = 0; i < count; i++) + { + var left = _prerelease[i]; + var right = other._prerelease[i]; + var leftIsNumeric = IsNumeric(left); + var rightIsNumeric = IsNumeric(right); + result = leftIsNumeric && rightIsNumeric + ? CompareNumericIdentifier(left, right) + : leftIsNumeric + ? -1 + : rightIsNumeric + ? 1 + : string.CompareOrdinal(left, right); + if (result != 0) + { + return result; + } + } + + return _prerelease.Length.CompareTo(other._prerelease.Length); + } + + internal static bool TryParse(string? value, out SemanticVersion version) + { + version = default; + if (value is null || value.Length == 0) + { + return false; + } + + var buildSeparator = value.IndexOf('+'); + if (buildSeparator >= 0) + { + if (value.IndexOf('+', buildSeparator + 1) >= 0 || !AreValidIdentifiers(value.Substring(buildSeparator + 1), allowNumericLeadingZeros: true)) + { + return false; + } + + value = value.Substring(0, buildSeparator); + } + + string[] prerelease = []; + var prereleaseSeparator = value.IndexOf('-'); + if (prereleaseSeparator >= 0) + { + var prereleaseText = value.Substring(prereleaseSeparator + 1); + if (!AreValidIdentifiers(prereleaseText, allowNumericLeadingZeros: false)) + { + return false; + } + + prerelease = prereleaseText.Split('.'); + value = value.Substring(0, prereleaseSeparator); + } + + var core = value.Split('.'); + if (core.Length != 3 || !IsValidCoreIdentifier(core[0]) || !IsValidCoreIdentifier(core[1]) || !IsValidCoreIdentifier(core[2])) + { + return false; + } + + version = new SemanticVersion(core[0], core[1], core[2], prerelease); + return true; + } + + private static bool AreValidIdentifiers(string value, bool allowNumericLeadingZeros) + { + var identifiers = value.Split('.'); + foreach (var identifier in identifiers) + { + if (identifier.Length == 0) + { + return false; + } + + foreach (var character in identifier) + { + if (!(character is >= '0' and <= '9' or >= 'A' and <= 'Z' or >= 'a' and <= 'z' or '-')) + { + return false; + } + } + + if (!allowNumericLeadingZeros && IsNumeric(identifier) && identifier.Length > 1 && identifier[0] == '0') + { + return false; + } + } + + return true; + } + + private static bool IsValidCoreIdentifier(string value) => + IsNumeric(value) && + (value.Length == 1 || value[0] != '0') && + ulong.TryParse(value, out _); + + private static bool IsNumeric(string value) + { + if (value.Length == 0) + { + return false; + } + + foreach (var character in value) + { + if (character is < '0' or > '9') + { + return false; + } + } + + return true; + } + + private static int CompareNumericIdentifier(string left, string right) => + left.Length != right.Length ? left.Length.CompareTo(right.Length) : string.CompareOrdinal(left, right); +} diff --git a/tracer/test/Datadog.Trace.TestHelpers/FeatureFlagsHelpers.cs b/tracer/test/Datadog.Trace.TestHelpers/FeatureFlagsHelpers.cs index 060555b3f168..8b031c89d6cd 100644 --- a/tracer/test/Datadog.Trace.TestHelpers/FeatureFlagsHelpers.cs +++ b/tracer/test/Datadog.Trace.TestHelpers/FeatureFlagsHelpers.cs @@ -23,9 +23,9 @@ internal static class FeatureFlagsHelpers internal const long SimpleStringSerialId = 100; internal const long ExposureSerialId = 108; - internal static Dictionary CreateAllFlags() + internal static FlagCollection CreateAllFlags() { - var flags = new Dictionary + var flags = new FlagCollection { ["simple-string"] = CreateSimpleFlag("simple-string", ValueType.String, "test-value", "on", serialId: SimpleStringSerialId), ["rule-based-flag"] = CreateRuleBasedFlag(), diff --git a/tracer/test/Datadog.Trace.Tests/Datadog.Trace.Tests.csproj b/tracer/test/Datadog.Trace.Tests/Datadog.Trace.Tests.csproj index 4cce0785c828..1eb4fd7514c9 100644 --- a/tracer/test/Datadog.Trace.Tests/Datadog.Trace.Tests.csproj +++ b/tracer/test/Datadog.Trace.Tests/Datadog.Trace.Tests.csproj @@ -83,8 +83,8 @@ - - + + diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/FeatureFlagsEvaluatorTests.Bundle.cs b/tracer/test/Datadog.Trace.Tests/FeatureFlags/FeatureFlagsEvaluatorTests.Bundle.cs index bd4e10f63280..66c2ebf5d8f2 100644 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/FeatureFlagsEvaluatorTests.Bundle.cs +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/FeatureFlagsEvaluatorTests.Bundle.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Drawing.Text; +using System.Linq; using Datadog.Trace.FeatureFlags; using Datadog.Trace.FeatureFlags.Rcm.Model; using Datadog.Trace.TestHelpers; @@ -27,6 +28,25 @@ public partial class FeatureFlagsEvaluatorTests internal static ServerConfiguration _config = ReadConfig(); #pragma warning restore SA1401 // Fields should be private + public enum CanonicalEvaluationReason + { + DEFAULT, + + STATIC, + + TARGETING_MATCH, + + SPLIT, + + DISABLED, + + CACHED, + + UNKNOWN, + + ERROR + } + [SkippableTheory] [MemberData(nameof(TestData))] public void BundledTest(string description, TestCase? testCase) @@ -49,7 +69,12 @@ public void BundledTest(string description, TestCase? testCase) } AssertEqual(testCase.Result.Value, result.Value); - AssertEqual(testCase.Result.Variant, result.Variant); + if (testCase.Result.Variant is not null) + { + AssertEqual(testCase.Result.Variant, result.Variant); + } + + Assert.Equal(testCase.Result.Reason, ToCanonicalReason(result.Reason)); Assert.NotNull(description); @@ -66,9 +91,9 @@ void AssertEqual(object? expected, object? obj) else if (type == Trace.FeatureFlags.ValueType.Json) { // Normalize BCL structure and Expected Json - var jsonTxt = JToken.Parse(JsonConvert.SerializeObject(obj)).ToString(); - var expectedTxt = expected?.ToString(); - Assert.Equal(expectedTxt, jsonTxt); + var actualJson = JToken.Parse(JsonConvert.SerializeObject(obj)); + var expectedJson = JToken.Parse(expected?.ToString() ?? "null"); + Assert.True(JToken.DeepEquals(expectedJson, actualJson), $"Expected {expectedJson}, got {actualJson}"); } else { @@ -93,15 +118,15 @@ private static Trace.FeatureFlags.ValueType GetVariationType(string? variationTy private static ServerConfiguration ReadConfig() { // Read config - var configContent = ResourceHelper.ReadAllText("resources.config.flags-v1.json"); + var configContent = ResourceHelper.ReadAllText("ffe_system_test_data.ufc-config.json"); var fullObject = JObject.Parse(configContent); - var dataToken = fullObject.SelectToken("data.attributes.flags"); - var flags = dataToken?.ToObject>(); - Assert.NotNull(flags); + var config = fullObject.ToObject(); + Assert.NotNull(config); + Assert.NotNull(config.Flags); - foreach (var flag in flags) + foreach (var flag in config.Flags) { - if (flag.Value.Allocations is null) { continue; } + if (flag.Value?.Allocations is null) { continue; } foreach (var allocation in flag.Value.Allocations) { allocation.StartAt = FixDateString(allocation.StartAt); @@ -138,18 +163,14 @@ private static ServerConfiguration ReadConfig() return dateString; } - var config = new ServerConfiguration { Flags = flags }; - return config; } private static List GetTestData() { - // This file should regularly be updated from here https://github.com/DataDog/experimental/blob/main/teams/asm/iast/redaction/suite/evidence-redaction-suite.yml - List testData = new List(); - foreach (var file in ResourceHelper.EnumFiles("resources.data")) + foreach (var file in ResourceHelper.EnumFiles("ffe_system_test_data.evaluation_cases").OrderBy(static file => file.Key)) { var testCases = JsonConvert.DeserializeObject>(file.Value); foreach (var testCase in testCases!) @@ -158,9 +179,26 @@ private static List GetTestData() } } + Assert.NotEmpty(testData); return testData; } + private static CanonicalEvaluationReason ToCanonicalReason(EvaluationReason reason) + { + return reason switch + { + EvaluationReason.Default => CanonicalEvaluationReason.DEFAULT, + EvaluationReason.Static => CanonicalEvaluationReason.STATIC, + EvaluationReason.TargetingMatch => CanonicalEvaluationReason.TARGETING_MATCH, + EvaluationReason.Split => CanonicalEvaluationReason.SPLIT, + EvaluationReason.Disabled => CanonicalEvaluationReason.DISABLED, + EvaluationReason.Cached => CanonicalEvaluationReason.CACHED, + EvaluationReason.Unknown => CanonicalEvaluationReason.UNKNOWN, + EvaluationReason.Error => CanonicalEvaluationReason.ERROR, + _ => throw new NotImplementedException(), + }; + } + public class TestCase { public string? Flag { get; set; } @@ -179,7 +217,7 @@ public class Evaluation { public object? Value { get; set; } - public EvaluationReason Reason { get; set; } + public CanonicalEvaluationReason Reason { get; set; } public string? Variant { get; set; } diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/FeatureFlagsEvaluatorTests.cs b/tracer/test/Datadog.Trace.Tests/FeatureFlags/FeatureFlagsEvaluatorTests.cs index 0312b9818a88..186f4fb0679b 100644 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/FeatureFlagsEvaluatorTests.cs +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/FeatureFlagsEvaluatorTests.cs @@ -119,62 +119,70 @@ public void EvaluateWithoutConfigReturnsProviderNotReadyAndDefault() } [Fact] - public void EvaluateWithMissingTargetingKeyReturnsTargetingKeyMissing() + public void EvaluateDistinguishesInvalidAndMissingFlags() { - var flags = new Dictionary - { - ["simple-string"] = FeatureFlagsHelpers.CreateSimpleFlag("simple-string", ValueType.String, "default", "on") - }; - - var evaluator = new FeatureFlagsEvaluator(null, new ServerConfiguration { Flags = flags }); - - var ctx = new EvaluationContext("user-123"); - var result = evaluator.Evaluate("simple-string", Trace.FeatureFlags.ValueType.String, "default", ctx); - Assert.Equal("default", result.Value); - Assert.Equal(EvaluationReason.Split, result.Reason); // Flag has shards → Split reason - Assert.Equal("on", result.Variant); - - var noTargettingKeyCtx = new EvaluationContext(string.Empty); // no targetingKey - result = evaluator.Evaluate("simple-string", Trace.FeatureFlags.ValueType.String, "default", noTargettingKeyCtx); - - Assert.Equal("default", result.Value); - Assert.Equal(EvaluationReason.Error, result.Reason); - Assert.Equal("TARGETING_KEY_MISSING", result.Error); - } + const string json = """ + { + "flags": { + "invalid-flag": { + "enabled": true, + "variationType": "STRING", + "allocations": "not-an-array" + }, + "valid-flag": { + "enabled": true, + "variationType": "STRING" + } + } + } + """; + var config = JsonConvert.DeserializeObject(json)!; + var evaluator = new FeatureFlagsEvaluator(null, config); + var ctx = new EvaluationContext("target"); - [Fact] - public void EvaluateWithUnknownFlagReturnsFlagNotFound() - { - var evaluator = new FeatureFlagsEvaluator(null, new ServerConfiguration()); - var ctx = new EvaluationContext("user-123"); - var result = evaluator.Evaluate("unknown", Trace.FeatureFlags.ValueType.String, "default", ctx); + var invalid = evaluator.Evaluate("invalid-flag", ValueType.String, "default", ctx); + var missing = evaluator.Evaluate("missing-flag", ValueType.String, "default", ctx); + var valid = evaluator.Evaluate("valid-flag", ValueType.String, "default", ctx); - Assert.Equal("default", result.Value); - Assert.Equal(EvaluationReason.Error, result.Reason); - Assert.Equal("FLAG_NOT_FOUND", result.Error); + Assert.Equal(EvaluationReason.Error, invalid.Reason); + Assert.Equal("PARSE_ERROR", invalid.Error); + Assert.Equal("PARSE_ERROR", invalid.FlagMetadata?["errorCode"]); + Assert.Equal(EvaluationReason.Error, missing.Reason); + Assert.Equal("FLAG_NOT_FOUND", missing.Error); + Assert.Equal(EvaluationReason.Default, valid.Reason); } [Fact] - public void EvaluateDisabledFlagReturnsDisabledReason() + public void MergeReplacesFlagParsingState() { - var flags = new Dictionary - { - ["disabled-flag"] = new Flag { Key = "disabled-flag", Enabled = false, VariationType = ValueType.Boolean } - }; - var evaluator = new FeatureFlagsEvaluator(null, new ServerConfiguration { Flags = flags }); - var ctx = new EvaluationContext("user"); - - var result = evaluator.Evaluate("disabled-flag", Trace.FeatureFlags.ValueType.Boolean, true, ctx); - - Assert.Equal(true, result.Value); - Assert.Equal(EvaluationReason.Disabled, result.Reason); - Assert.Null(result.Error); + var originalFlag = new Flag(); + var replacementFlag = new Flag(); + var flags = new FlagCollection { ["flag"] = originalFlag }; + var invalidFlags = JsonConvert.DeserializeObject(""" + { + "flags": { + "flag": { + "allocations": "not-an-array" + } + } + } + """)!.Flags!; + + flags.Merge(invalidFlags); + Assert.Equal(FlagLookupResult.Invalid, flags.Find("flag", out var invalid)); + Assert.Null(invalid); + + flags.Merge(new FlagCollection { ["flag"] = replacementFlag }); + Assert.Equal(FlagLookupResult.Found, flags.Find("flag", out var valid)); + Assert.Same(replacementFlag, valid); + Assert.Equal(FlagLookupResult.NotFound, flags.Find("missing", out var missing)); + Assert.Null(missing); } [Fact] public void EvaluateFlagWithTypeMismatchReturnsTypeMismatchError() { - var flags = new Dictionary + var flags = new FlagCollection { ["null-allocation"] = new Flag { Key = "target", Enabled = true, VariationType = ValueType.String }, ["empty-allocation"] = new Flag { Key = "target", Enabled = true, VariationType = ValueType.String, Allocations = new List() }, @@ -193,26 +201,6 @@ public void EvaluateFlagWithTypeMismatchReturnsTypeMismatchError() Assert.Equal("TYPE_MISMATCH", result2.FlagMetadata?["errorCode"]); } - [Fact] - public void EvaluateFlagWithoutAllocationsReturnsDefaultValue() - { - var flags = new Dictionary - { - ["null-allocation"] = new Flag { Key = "target", Enabled = true, VariationType = ValueType.String }, - ["empty-allocation"] = new Flag { Key = "target", Enabled = true, VariationType = ValueType.String, Allocations = new List() }, - }; - var evaluator = new FeatureFlagsEvaluator(null, new ServerConfiguration { Flags = flags }); - var ctx = new EvaluationContext("allocation"); - - var result1 = evaluator.Evaluate("null-allocation", Trace.FeatureFlags.ValueType.String, 23, ctx); - Assert.Equal(23, result1.Value); - Assert.Equal(EvaluationReason.Default, result1.Reason); - - var result2 = evaluator.Evaluate("empty-allocation", Trace.FeatureFlags.ValueType.String, 23, ctx); - Assert.Equal(23, result2.Value); - Assert.Equal(EvaluationReason.Default, result2.Reason); - } - // --------------------------------------------------------------------- // FlattenContext tests // --------------------------------------------------------------------- @@ -265,86 +253,14 @@ public void FlattenContextFlattensListsAndDictionarys(Dictionary - { - ["simple-string"] = FeatureFlagsHelpers.CreateSimpleFlag("simple-string", ValueType.String, "test-value", "on") - }; - - var evaluator = new FeatureFlagsEvaluator(null, new ServerConfiguration { Flags = flags }); - var ctx = new EvaluationContext("user-123"); - - var result = evaluator.Evaluate("simple-string", Trace.FeatureFlags.ValueType.String, "default", ctx); - - Assert.Equal("test-value", result.Value); - Assert.Equal(EvaluationReason.Split, result.Reason); - Assert.Equal("on", result.Variant); - } - - [Fact] - public void EvaluateRuleBasedFlagMatchesEmailPremium() - { - var flags = new Dictionary - { - ["rule-based-flag"] = FeatureFlagsHelpers.CreateRuleBasedFlag() - }; - - var evaluator = new FeatureFlagsEvaluator(null, new ServerConfiguration { Flags = flags }); - var ctx = new EvaluationContext("user-premium", new Dictionary { { "email", "john@company.com" } }); - - var result = evaluator.Evaluate("rule-based-flag", Trace.FeatureFlags.ValueType.String, "default", ctx); - - Assert.Equal("premium", result.Value); - Assert.Equal(EvaluationReason.TargetingMatch, result.Reason); - Assert.Equal("premium", result.Variant); - } - - [Fact] - public void EvaluateNumericRuleFlagMatchesScoreGte800() - { - var flags = new Dictionary - { - ["numeric-rule-flag"] = FeatureFlagsHelpers.CreateNumericRuleFlag() - }; - - var evaluator = new FeatureFlagsEvaluator(null, new ServerConfiguration { Flags = flags }); - var ctx = new EvaluationContext("user-vip", new Dictionary { { "score", 850 } }); - - var result = evaluator.Evaluate("numeric-rule-flag", Trace.FeatureFlags.ValueType.String, "default", ctx); - - Assert.Equal("vip", result.Value); - Assert.Equal(EvaluationReason.TargetingMatch, result.Reason); - Assert.Equal("vip", result.Variant); - } - - [Fact] - public void EvaluateTimeBasedFlagWithExpiredAllocationReturnsDefaultReason() - { - var flags = new Dictionary - { - ["time-based-flag"] = FeatureFlagsHelpers.CreateTimeBasedFlag() - }; - - var evaluator = new FeatureFlagsEvaluator(null, new ServerConfiguration { Flags = flags }); - var ctx = new EvaluationContext("user"); - - var result = evaluator.Evaluate("time-based-flag", Trace.FeatureFlags.ValueType.String, "default", ctx); - - Assert.Equal("default", result.Value); - Assert.Equal(EvaluationReason.Default, result.Reason); - } - [Fact] public void EvaluateExposureFlagLogsExposureEvent() { - var flags = new Dictionary + var flags = new FlagCollection { ["exposure-flag"] = FeatureFlagsHelpers.CreateExposureFlag() }; @@ -377,7 +293,7 @@ public void EvaluateExposureFlagLogsExposureEvent() public void EvaluateTimeBasedFlagWithVariousIso8601DateFormats(string startAt, string endAt) { var flag = CreateTimeBasedFlagWithDates("iso8601-flag", startAt, endAt); - var flags = new Dictionary { ["iso8601-flag"] = flag }; + var flags = new FlagCollection { ["iso8601-flag"] = flag }; var evaluator = new FeatureFlagsEvaluator(null, new ServerConfiguration { Flags = flags }); var ctx = new EvaluationContext("user-123"); @@ -386,7 +302,7 @@ public void EvaluateTimeBasedFlagWithVariousIso8601DateFormats(string startAt, s // The allocation is active (2020-2099 dates), so it should match Assert.Equal("time-limited", result.Value); - Assert.Equal(EvaluationReason.Static, result.Reason); // No rules, no shards → Static + Assert.Equal(EvaluationReason.Default, result.Reason); // Temporal allocation with one unsharded split → Default Assert.Equal("time-limited", result.Variant); } @@ -397,7 +313,7 @@ public void EvaluateTimeBasedFlagWithVariousIso8601DateFormats(string startAt, s public void EvaluateTimeBasedFlagWithExpiredMicrosecondDatesReturnsDefault(string startAt, string endAt) { var flag = CreateTimeBasedFlagWithDates("expired-flag", startAt, endAt); - var flags = new Dictionary { ["expired-flag"] = flag }; + var flags = new FlagCollection { ["expired-flag"] = flag }; var evaluator = new FeatureFlagsEvaluator(null, new ServerConfiguration { Flags = flags }); var ctx = new EvaluationContext("user-123"); @@ -419,7 +335,7 @@ public void EvaluateTimeBasedFlagWithNonStandardDateFormatsStillParses(string st // This test documents this behavior - since dates come from our controlled backend, // accepting broader formats is acceptable. var flag = CreateTimeBasedFlagWithDates("non-standard-flag", startAt, endAt); - var flags = new Dictionary { ["non-standard-flag"] = flag }; + var flags = new FlagCollection { ["non-standard-flag"] = flag }; var evaluator = new FeatureFlagsEvaluator(null, new ServerConfiguration { Flags = flags }); var ctx = new EvaluationContext("user-123"); @@ -428,7 +344,7 @@ public void EvaluateTimeBasedFlagWithNonStandardDateFormatsStillParses(string st // The allocation is active (2020-2099 dates), so it should match Assert.Equal("time-limited", result.Value); - Assert.Equal(EvaluationReason.Static, result.Reason); // No rules, no shards → Static + Assert.Equal(EvaluationReason.Default, result.Reason); // Temporal allocation with one unsharded split → Default Assert.Equal("time-limited", result.Variant); } @@ -445,7 +361,7 @@ public void EvaluateTimeBasedFlagWithNonStandardDateFormatsStillParses(string st public void EvaluateTimeBasedFlagWithInvalidDateReturnsParseError(string startAt, string endAt) { var flag = CreateTimeBasedFlagWithDates("invalid-flag", startAt, endAt); - var flags = new Dictionary { ["invalid-flag"] = flag }; + var flags = new FlagCollection { ["invalid-flag"] = flag }; var evaluator = new FeatureFlagsEvaluator(null, new ServerConfiguration { Flags = flags }); var ctx = new EvaluationContext("user-123"); @@ -477,7 +393,7 @@ public void EvaluateNoRulesNoShardsReturnsStaticReason() var alloc = new Allocation { Key = "static-alloc", Rules = null, Splits = splits, DoLog = false }; var flag = new Flag { Key = "static-flag", Enabled = true, VariationType = ValueType.String, Variations = variants, Allocations = new List { alloc } }; - var flags = new Dictionary { ["static-flag"] = flag }; + var flags = new FlagCollection { ["static-flag"] = flag }; var evaluator = new FeatureFlagsEvaluator(null, new ServerConfiguration { Flags = flags }); var ctx = new EvaluationContext("any-user"); @@ -513,7 +429,7 @@ public void EvaluateNoRulesWithShardsReturnsSplitReason() var alloc = new Allocation { Key = "split-alloc", Rules = null, Splits = splits, DoLog = false }; var flag = new Flag { Key = "split-flag", Enabled = true, VariationType = ValueType.String, Variations = variants, Allocations = new List { alloc } }; - var flags = new Dictionary { ["split-flag"] = flag }; + var flags = new FlagCollection { ["split-flag"] = flag }; var evaluator = new FeatureFlagsEvaluator(null, new ServerConfiguration { Flags = flags }); var ctx = new EvaluationContext("user-in-bucket"); diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/FeatureFlagsModuleTests.cs b/tracer/test/Datadog.Trace.Tests/FeatureFlags/FeatureFlagsModuleTests.cs index f45e9f02481d..1488e0c2bac8 100644 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/FeatureFlagsModuleTests.cs +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/FeatureFlagsModuleTests.cs @@ -37,7 +37,7 @@ public void UpdateRemoteConfig_WithEmptyList_InvokesCallbackAndReturnsProviderNo // First, send a valid config so evaluator is created var configJson = JsonConvert.SerializeObject(new ServerConfiguration { - Flags = new Dictionary + Flags = new FlagCollection { ["test-flag"] = new Flag { Key = "test-flag", Enabled = true, VariationType = FeatureFlagsValueType.Boolean } } diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/SOURCE.md b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/SOURCE.md new file mode 100644 index 000000000000..1360501bfd61 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/SOURCE.md @@ -0,0 +1,10 @@ +# FFE Fixture Snapshot + +These files are copied from the canonical FFE fixture repository. + +Canonical source: https://github.com/DataDog/ffe-system-test-data +Source commit: ea8b5cc5ce335109f11f3efbc5fd608f98a3ca54 + +Do not edit these fixtures directly in dd-trace-dotnet. Add or update shared FFE behavior in ffe-system-test-data first, then refresh this snapshot. + +The weekly update workflow runs `./tracer/build.sh UpdateFfeFixtures` and opens a draft test PR only when the allowed fixture contents change. \ No newline at end of file diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-boolean-false-assignment.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-boolean-false-assignment.json new file mode 100644 index 000000000000..ab718f5bee10 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/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/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-boolean-one-of-matches.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-boolean-one-of-matches.json similarity index 58% rename from tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-boolean-one-of-matches.json rename to tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-boolean-one-of-matches.json index 6bfbf0effad9..392ec97ec0fb 100644 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-boolean-one-of-matches.json +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-boolean-one-of-matches.json @@ -1,240 +1,208 @@ [ { - "flag": "boolean-one-of-matches", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "alice", "attributes": { "one_of_flag": true }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", "result": { - "value": 1, - "variant": "1", - "flagMetadata": { - "allocationKey": "1-for-one-of", - "variationType": "number", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": 1 + }, + "targetingKey": "alice", + "variationType": "INTEGER" }, { - "flag": "boolean-one-of-matches", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "bob", "attributes": { "one_of_flag": false }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", "result": { + "reason": "DEFAULT", "value": 0 - } + }, + "targetingKey": "bob", + "variationType": "INTEGER" }, { - "flag": "boolean-one-of-matches", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "charlie", "attributes": { "one_of_flag": "True" }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", "result": { + "reason": "DEFAULT", "value": 0 - } + }, + "targetingKey": "charlie", + "variationType": "INTEGER" }, { - "flag": "boolean-one-of-matches", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "derek", "attributes": { "matches_flag": true }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", "result": { - "value": 2, - "variant": "2", - "flagMetadata": { - "allocationKey": "2-for-matches", - "variationType": "number", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": 2 + }, + "targetingKey": "derek", + "variationType": "INTEGER" }, { - "flag": "boolean-one-of-matches", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "erica", "attributes": { "matches_flag": false }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", "result": { + "reason": "DEFAULT", "value": 0 - } + }, + "targetingKey": "erica", + "variationType": "INTEGER" }, { - "flag": "boolean-one-of-matches", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "frank", "attributes": { "not_matches_flag": false }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", "result": { + "reason": "DEFAULT", "value": 0 - } + }, + "targetingKey": "frank", + "variationType": "INTEGER" }, { - "flag": "boolean-one-of-matches", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "george", "attributes": { "not_matches_flag": true }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", "result": { - "value": 4, - "variant": "4", - "flagMetadata": { - "allocationKey": "4-for-not-matches", - "variationType": "number", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": 4 + }, + "targetingKey": "george", + "variationType": "INTEGER" }, { - "flag": "boolean-one-of-matches", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "haley", "attributes": { "not_matches_flag": "False" }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", "result": { - "value": 4, - "variant": "4", - "flagMetadata": { - "allocationKey": "4-for-not-matches", - "variationType": "number", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": 4 + }, + "targetingKey": "haley", + "variationType": "INTEGER" }, { - "flag": "boolean-one-of-matches", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "ivy", "attributes": { "not_one_of_flag": true }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", "result": { - "value": 3, - "variant": "3", - "flagMetadata": { - "allocationKey": "3-for-not-one-of", - "variationType": "number", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": 3 + }, + "targetingKey": "ivy", + "variationType": "INTEGER" }, { - "flag": "boolean-one-of-matches", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "julia", "attributes": { "not_one_of_flag": false }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", "result": { + "reason": "DEFAULT", "value": 0 - } + }, + "targetingKey": "julia", + "variationType": "INTEGER" }, { - "flag": "boolean-one-of-matches", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "kim", "attributes": { "not_one_of_flag": "False" }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", "result": { - "value": 3, - "variant": "3", - "flagMetadata": { - "allocationKey": "3-for-not-one-of", - "variationType": "number", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": 3 + }, + "targetingKey": "kim", + "variationType": "INTEGER" }, { - "flag": "boolean-one-of-matches", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "lucas", "attributes": { "not_one_of_flag": "true" }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", "result": { - "value": 3, - "variant": "3", - "flagMetadata": { - "allocationKey": "3-for-not-one-of", - "variationType": "number", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": 3 + }, + "targetingKey": "lucas", + "variationType": "INTEGER" }, { - "flag": "boolean-one-of-matches", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "mike", "attributes": { "not_one_of_flag": "false" }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", "result": { + "reason": "DEFAULT", "value": 0 - } + }, + "targetingKey": "mike", + "variationType": "INTEGER" }, { - "flag": "boolean-one-of-matches", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "nicole", "attributes": { "null_flag": "null" }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", "result": { - "value": 5, - "variant": "5", - "flagMetadata": { - "allocationKey": "5-for-matches-null", - "variationType": "number", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": 5 + }, + "targetingKey": "nicole", + "variationType": "INTEGER" }, { - "flag": "boolean-one-of-matches", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "owen", "attributes": { "null_flag": null }, + "defaultValue": 0, + "flag": "boolean-one-of-matches", "result": { + "reason": "DEFAULT", "value": 0 - } + }, + "targetingKey": "owen", + "variationType": "INTEGER" }, { - "flag": "boolean-one-of-matches", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "pete", "attributes": {}, + "defaultValue": 0, + "flag": "boolean-one-of-matches", "result": { + "reason": "DEFAULT", "value": 0 - } + }, + "targetingKey": "pete", + "variationType": "INTEGER" } ] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-comparator-operator-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-comparator-operator-flag.json similarity index 51% rename from tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-comparator-operator-flag.json rename to tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-comparator-operator-flag.json index a5c8ef07cd40..e4daa2de7c21 100644 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-comparator-operator-flag.json +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-comparator-operator-flag.json @@ -1,82 +1,69 @@ [ { - "flag": "comparator-operator-test", - "variationType": "STRING", - "defaultValue": "unknown", - "targetingKey": "alice", "attributes": { - "size": 5, - "country": "US" + "country": "US", + "size": 5 }, + "defaultValue": "unknown", + "flag": "comparator-operator-test", "result": { - "value": "small", - "variant": "small", - "flagMetadata": { - "allocationKey": "small-size", - "variationType": "string", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": "small" + }, + "targetingKey": "alice", + "variationType": "STRING" }, { - "flag": "comparator-operator-test", - "variationType": "STRING", - "defaultValue": "unknown", - "targetingKey": "bob", "attributes": { - "size": 10, - "country": "Canada" + "country": "Canada", + "size": 10 }, + "defaultValue": "unknown", + "flag": "comparator-operator-test", "result": { - "value": "medium", - "variant": "medium", - "flagMetadata": { - "allocationKey": "medum-size", - "variationType": "string", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": "medium" + }, + "targetingKey": "bob", + "variationType": "STRING" }, { - "flag": "comparator-operator-test", - "variationType": "STRING", - "defaultValue": "unknown", - "targetingKey": "charlie", "attributes": { "size": 25 }, + "defaultValue": "unknown", + "flag": "comparator-operator-test", "result": { + "reason": "DEFAULT", "value": "unknown" - } + }, + "targetingKey": "charlie", + "variationType": "STRING" }, { - "flag": "comparator-operator-test", - "variationType": "STRING", - "defaultValue": "unknown", - "targetingKey": "david", "attributes": { "size": 26 }, + "defaultValue": "unknown", + "flag": "comparator-operator-test", "result": { - "value": "large", - "variant": "large", - "flagMetadata": { - "allocationKey": "large-size", - "variationType": "string", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": "large" + }, + "targetingKey": "david", + "variationType": "STRING" }, { - "flag": "comparator-operator-test", - "variationType": "STRING", - "defaultValue": "unknown", - "targetingKey": "elize", "attributes": { "country": "UK" }, + "defaultValue": "unknown", + "flag": "comparator-operator-test", "result": { + "reason": "DEFAULT", "value": "unknown" - } + }, + "targetingKey": "elize", + "variationType": "STRING" } ] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-disabled-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-disabled-flag.json similarity index 59% rename from tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-disabled-flag.json rename to tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-disabled-flag.json index 0da79189ade8..208e5c96943f 100644 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-disabled-flag.json +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-disabled-flag.json @@ -1,40 +1,43 @@ [ { - "flag": "disabled_flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "alice", "attributes": { - "email": "alice@mycompany.com", - "country": "US" + "country": "US", + "email": "alice@mycompany.com" }, + "defaultValue": 0, + "flag": "disabled_flag", "result": { + "reason": "DISABLED", "value": 0 - } + }, + "targetingKey": "alice", + "variationType": "INTEGER" }, { - "flag": "disabled_flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "bob", "attributes": { - "email": "bob@example.com", - "country": "Canada" + "country": "Canada", + "email": "bob@example.com" }, + "defaultValue": 0, + "flag": "disabled_flag", "result": { + "reason": "DISABLED", "value": 0 - } + }, + "targetingKey": "bob", + "variationType": "INTEGER" }, { - "flag": "disabled_flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "charlie", "attributes": { "age": 50 }, + "defaultValue": 0, + "flag": "disabled_flag", "result": { + "reason": "DISABLED", "value": 0 - } + }, + "targetingKey": "charlie", + "variationType": "INTEGER" } ] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-empty-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-empty-flag.json similarity index 63% rename from tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-empty-flag.json rename to tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-empty-flag.json index 52100b1fe47d..18ee5381fdcc 100644 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-empty-flag.json +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-empty-flag.json @@ -1,40 +1,43 @@ [ { - "flag": "empty_flag", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "alice", "attributes": { - "email": "alice@mycompany.com", - "country": "US" + "country": "US", + "email": "alice@mycompany.com" }, + "defaultValue": "default_value", + "flag": "empty_flag", "result": { + "reason": "DEFAULT", "value": "default_value" - } + }, + "targetingKey": "alice", + "variationType": "STRING" }, { - "flag": "empty_flag", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "bob", "attributes": { - "email": "bob@example.com", - "country": "Canada" + "country": "Canada", + "email": "bob@example.com" }, + "defaultValue": "default_value", + "flag": "empty_flag", "result": { + "reason": "DEFAULT", "value": "default_value" - } + }, + "targetingKey": "bob", + "variationType": "STRING" }, { - "flag": "empty_flag", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "charlie", "attributes": { "age": 50 }, + "defaultValue": "default_value", + "flag": "empty_flag", "result": { + "reason": "DEFAULT", "value": "default_value" - } + }, + "targetingKey": "charlie", + "variationType": "STRING" } ] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-empty-string-variation.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-empty-string-variation.json new file mode 100644 index 000000000000..f1fa3994af20 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/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/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-falsy-value-assignments.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-falsy-value-assignments.json new file mode 100644 index 000000000000..6a8cee51bcc4 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/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/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-flag-with-empty-string.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-flag-with-empty-string.json new file mode 100644 index 000000000000..6a5d9cd62fd7 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/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/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-integer-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-integer-flag.json new file mode 100644 index 000000000000..8ff11aec1fc9 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/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/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-invalid-condition-operands.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-invalid-condition-operands.json new file mode 100644 index 000000000000..be2263814558 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-invalid-condition-operands.json @@ -0,0 +1,59 @@ +[ + { + "description": "GT requires a numeric configured operand. A flag with a string operand must return a parse error rather than falling through to the catch-all allocation.", + "attributes": { + "age": 42 + }, + "defaultValue": "default", + "flag": "invalid-gt-condition-flag", + "result": { + "errorCode": "PARSE_ERROR", + "reason": "ERROR", + "value": "default" + }, + "targetingKey": "invalid-gt", + "variationType": "STRING" + }, + { + "description": "ONE_OF requires an array configured operand. A flag with a scalar operand must return a parse error rather than falling through to the catch-all allocation.", + "attributes": { + "role": "admin" + }, + "defaultValue": "default", + "flag": "invalid-one-of-condition-flag", + "result": { + "errorCode": "PARSE_ERROR", + "reason": "ERROR", + "value": "default" + }, + "targetingKey": "invalid-one-of", + "variationType": "STRING" + }, + { + "description": "IS_NULL requires a boolean configured operand. A flag with a string operand must return a parse error rather than falling through to the catch-all allocation.", + "attributes": { + "deleted_at": null + }, + "defaultValue": "default", + "flag": "invalid-is-null-condition-flag", + "result": { + "errorCode": "PARSE_ERROR", + "reason": "ERROR", + "value": "default" + }, + "targetingKey": "invalid-is-null", + "variationType": "STRING" + }, + { + "description": "A valid flag in the same configuration must still evaluate after malformed condition operands are isolated.", + "attributes": {}, + "defaultValue": "default", + "flag": "valid-flag-after-invalid-config", + "result": { + "reason": "STATIC", + "value": "expected" + }, + "targetingKey": "valid-neighbor", + "variationType": "STRING" + } +] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-invalid-regex-isolation.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-invalid-regex-isolation.json new file mode 100644 index 000000000000..3ad596cbf063 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-invalid-regex-isolation.json @@ -0,0 +1,17 @@ +[ + { + "description": "The malformed flag uses the invalid regex *@datadoghq.com before a catch-all allocation. SDKs must return a parse error without poisoning the full configuration.", + "attributes": { + "email": "harish@datadoghq.com" + }, + "defaultValue": "default", + "flag": "invalid-regex-flag", + "result": { + "errorCode": "PARSE_ERROR", + "reason": "ERROR", + "value": "default" + }, + "targetingKey": "harish", + "variationType": "STRING" + } +] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-invalid-shard-bounds-isolation.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-invalid-shard-bounds-isolation.json new file mode 100644 index 000000000000..ca8553f099c3 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-invalid-shard-bounds-isolation.json @@ -0,0 +1,40 @@ +[ + { + "description": "The malformed flag has totalShards above the unsigned 32-bit range. SDKs must return a parse error without poisoning the full configuration.", + "attributes": {}, + "defaultValue": "default", + "flag": "overflow-total-shards-flag", + "result": { + "errorCode": "PARSE_ERROR", + "reason": "ERROR", + "value": "default" + }, + "targetingKey": "alice", + "variationType": "STRING" + }, + { + "description": "The malformed flag has a negative shard range start. SDKs must return a parse error without poisoning the full configuration.", + "attributes": {}, + "defaultValue": "default", + "flag": "negative-shard-range-start-flag", + "result": { + "errorCode": "PARSE_ERROR", + "reason": "ERROR", + "value": "default" + }, + "targetingKey": "alice", + "variationType": "STRING" + }, + { + "description": "A valid flag in the same config must still evaluate after invalid shard-bound flags are skipped.", + "attributes": {}, + "defaultValue": "default", + "flag": "valid-flag-after-invalid-config", + "result": { + "reason": "STATIC", + "value": "expected" + }, + "targetingKey": "alice", + "variationType": "STRING" + } +] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-kill-switch-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-kill-switch-flag.json new file mode 100644 index 000000000000..3af700dc711e --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/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/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-malformed-flag-isolation.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-malformed-flag-isolation.json new file mode 100644 index 000000000000..41672357c23b --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-malformed-flag-isolation.json @@ -0,0 +1,27 @@ +[ + { + "description": "The malformed flag has allocations encoded as a string instead of an array. SDKs must return a parse error without poisoning the full configuration.", + "attributes": {}, + "defaultValue": "default", + "flag": "malformed-allocations-flag", + "result": { + "errorCode": "PARSE_ERROR", + "reason": "ERROR", + "value": "default" + }, + "targetingKey": "alice", + "variationType": "STRING" + }, + { + "description": "A valid flag in the same config must still evaluate after the malformed flag is skipped.", + "attributes": {}, + "defaultValue": "default", + "flag": "valid-flag-after-invalid-config", + "result": { + "reason": "STATIC", + "value": "expected" + }, + "targetingKey": "alice", + "variationType": "STRING" + } +] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-microsecond-date-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-microsecond-date-flag.json new file mode 100644 index 000000000000..3dba337ad027 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-microsecond-date-flag.json @@ -0,0 +1,39 @@ +[ + { + "attributes": {}, + "defaultValue": "unknown", + "flag": "microsecond-date-test", + "result": { + "reason": "DEFAULT", + "value": "active" + }, + "targetingKey": "alice", + "variationType": "STRING" + }, + { + "attributes": { + "country": "US" + }, + "defaultValue": "unknown", + "flag": "microsecond-date-test", + "result": { + "reason": "DEFAULT", + "value": "active" + }, + "targetingKey": "bob", + "variationType": "STRING" + }, + { + "attributes": { + "version": "1.0.0" + }, + "defaultValue": "unknown", + "flag": "microsecond-date-test", + "result": { + "reason": "DEFAULT", + "value": "active" + }, + "targetingKey": "charlie", + "variationType": "STRING" + } +] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-missing-split-shards-isolation.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-missing-split-shards-isolation.json new file mode 100644 index 000000000000..d6dfeb180ea1 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-missing-split-shards-isolation.json @@ -0,0 +1,27 @@ +[ + { + "description": "The malformed flag has a split that omits required shards. SDKs must return a parse error without poisoning the full configuration.", + "attributes": {}, + "defaultValue": "default", + "flag": "missing-split-shards-flag", + "result": { + "errorCode": "PARSE_ERROR", + "reason": "ERROR", + "value": "default" + }, + "targetingKey": "alice", + "variationType": "STRING" + }, + { + "description": "A valid flag in the same config must still evaluate after the missing-shards flag is skipped.", + "attributes": {}, + "defaultValue": "default", + "flag": "valid-flag-after-invalid-config", + "result": { + "reason": "STATIC", + "value": "expected" + }, + "targetingKey": "alice", + "variationType": "STRING" + } +] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-new-user-onboarding-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-new-user-onboarding-flag.json similarity index 50% rename from tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-new-user-onboarding-flag.json rename to tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-new-user-onboarding-flag.json index 3845597270eb..bb08523de4e1 100644 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-new-user-onboarding-flag.json +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-new-user-onboarding-flag.json @@ -1,420 +1,344 @@ [ { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "alice", "attributes": { - "email": "alice@mycompany.com", - "country": "US" + "country": "US", + "email": "alice@mycompany.com" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { - "value": "green", - "variant": "green", - "flagMetadata": { - "allocationKey": "internal users", - "variationType": "string", - "doLog": false - } - } + "reason": "TARGETING_MATCH", + "value": "green" + }, + "targetingKey": "alice", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "bob", "attributes": { - "email": "bob@example.com", - "country": "Canada" + "country": "Canada", + "email": "bob@example.com" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { + "reason": "DEFAULT", "value": "default" - } + }, + "targetingKey": "bob", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "charlie", "attributes": { "age": 50 }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { + "reason": "DEFAULT", "value": "default" - } + }, + "targetingKey": "charlie", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "debra", "attributes": { - "email": "test@test.com", + "age": 25, "country": "Mexico", - "age": 25 + "email": "test@test.com" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { - "value": "blue", - "variant": "blue", - "flagMetadata": { - "allocationKey": "rollout", - "variationType": "string", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": "blue" + }, + "targetingKey": "debra", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "zach", "attributes": { - "email": "test@test.com", + "age": 25, "country": "Mexico", - "age": 25 + "email": "test@test.com" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { - "value": "purple", - "variant": "purple", - "flagMetadata": { - "allocationKey": "id rule", - "variationType": "string", - "doLog": false - } - } + "reason": "TARGETING_MATCH", + "value": "purple" + }, + "targetingKey": "zach", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "zach", "attributes": { - "id": "override-id", - "email": "test@test.com", + "age": 25, "country": "Mexico", - "age": 25 + "email": "test@test.com", + "id": "override-id" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { - "value": "blue", - "variant": "blue", - "flagMetadata": { - "allocationKey": "rollout", - "variationType": "string", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": "blue" + }, + "targetingKey": "zach", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "Zach", "attributes": { - "email": "test@test.com", + "age": 25, "country": "Mexico", - "age": 25 + "email": "test@test.com" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { + "reason": "DEFAULT", "value": "default" - } + }, + "targetingKey": "Zach", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "1", "attributes": {}, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { + "reason": "DEFAULT", "value": "default" - } + }, + "targetingKey": "1", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "2", "attributes": { "country": "Mexico" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { - "value": "blue", - "variant": "blue", - "flagMetadata": { - "allocationKey": "rollout", - "variationType": "string", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": "blue" + }, + "targetingKey": "2", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "3", "attributes": { - "country": "UK", - "age": 33 + "age": 33, + "country": "UK" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { - "value": "control", - "variant": "control", - "flagMetadata": { - "allocationKey": "experiment", - "variationType": "string", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": "control" + }, + "targetingKey": "3", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "4", "attributes": { "country": "Germany" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { - "value": "red", - "variant": "red", - "flagMetadata": { - "allocationKey": "experiment", - "variationType": "string", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": "red" + }, + "targetingKey": "4", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "5", "attributes": { "country": "Germany" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { - "value": "yellow", - "variant": "yellow", - "flagMetadata": { - "allocationKey": "experiment", - "variationType": "string", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": "yellow" + }, + "targetingKey": "5", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "6", "attributes": { "country": "Germany" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { - "value": "yellow", - "variant": "yellow", - "flagMetadata": { - "allocationKey": "experiment", - "variationType": "string", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": "yellow" + }, + "targetingKey": "6", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "7", "attributes": { "country": "US" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { - "value": "blue", - "variant": "blue", - "flagMetadata": { - "allocationKey": "rollout", - "variationType": "string", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": "blue" + }, + "targetingKey": "7", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "8", "attributes": { "country": "Italy" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { - "value": "red", - "variant": "red", - "flagMetadata": { - "allocationKey": "experiment", - "variationType": "string", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": "red" + }, + "targetingKey": "8", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "9", "attributes": { "email": "email@email.com" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { + "reason": "DEFAULT", "value": "default" - } + }, + "targetingKey": "9", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "10", "attributes": {}, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { + "reason": "DEFAULT", "value": "default" - } + }, + "targetingKey": "10", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "11", "attributes": {}, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { + "reason": "DEFAULT", "value": "default" - } + }, + "targetingKey": "11", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "12", "attributes": { "country": "US" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { - "value": "blue", - "variant": "blue", - "flagMetadata": { - "allocationKey": "rollout", - "variationType": "string", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": "blue" + }, + "targetingKey": "12", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "13", "attributes": { "country": "Canada" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { - "value": "blue", - "variant": "blue", - "flagMetadata": { - "allocationKey": "rollout", - "variationType": "string", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": "blue" + }, + "targetingKey": "13", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "14", "attributes": {}, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { + "reason": "DEFAULT", "value": "default" - } + }, + "targetingKey": "14", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "15", "attributes": { "country": "Denmark" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { - "value": "yellow", - "variant": "yellow", - "flagMetadata": { - "allocationKey": "experiment", - "variationType": "string", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": "yellow" + }, + "targetingKey": "15", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "16", "attributes": { "country": "Norway" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { - "value": "control", - "variant": "control", - "flagMetadata": { - "allocationKey": "experiment", - "variationType": "string", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": "control" + }, + "targetingKey": "16", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "17", "attributes": { "country": "UK" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { - "value": "control", - "variant": "control", - "flagMetadata": { - "allocationKey": "experiment", - "variationType": "string", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": "control" + }, + "targetingKey": "17", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "18", "attributes": { "country": "UK" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { + "reason": "DEFAULT", "value": "default" - } + }, + "targetingKey": "18", + "variationType": "STRING" }, { - "flag": "new-user-onboarding", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "19", "attributes": { "country": "UK" }, + "defaultValue": "default", + "flag": "new-user-onboarding", "result": { - "value": "red", - "variant": "red", - "flagMetadata": { - "allocationKey": "experiment", - "variationType": "string", - "doLog": true - } - } + "reason": "TARGETING_MATCH", + "value": "red" + }, + "targetingKey": "19", + "variationType": "STRING" } ] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-no-allocations-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-no-allocations-flag.json similarity index 68% rename from tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-no-allocations-flag.json rename to tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-no-allocations-flag.json index 132c39db32af..7d985b8efd46 100644 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-no-allocations-flag.json +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-no-allocations-flag.json @@ -1,52 +1,55 @@ [ { - "flag": "no_allocations_flag", - "variationType": "JSON", + "attributes": { + "country": "US", + "email": "alice@mycompany.com" + }, "defaultValue": { "hello": "world" }, - "targetingKey": "alice", - "attributes": { - "email": "alice@mycompany.com", - "country": "US" - }, + "flag": "no_allocations_flag", "result": { + "reason": "DEFAULT", "value": { "hello": "world" } - } + }, + "targetingKey": "alice", + "variationType": "JSON" }, { - "flag": "no_allocations_flag", - "variationType": "JSON", + "attributes": { + "country": "Canada", + "email": "bob@example.com" + }, "defaultValue": { "hello": "world" }, - "targetingKey": "bob", - "attributes": { - "email": "bob@example.com", - "country": "Canada" - }, + "flag": "no_allocations_flag", "result": { + "reason": "DEFAULT", "value": { "hello": "world" } - } + }, + "targetingKey": "bob", + "variationType": "JSON" }, { - "flag": "no_allocations_flag", - "variationType": "JSON", - "defaultValue": { - "hello": "world" - }, - "targetingKey": "charlie", "attributes": { "age": 50 }, + "defaultValue": { + "hello": "world" + }, + "flag": "no_allocations_flag", "result": { + "reason": "DEFAULT", "value": { "hello": "world" } - } + }, + "targetingKey": "charlie", + "variationType": "JSON" } ] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-null-operator-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-null-operator-flag.json new file mode 100644 index 000000000000..8063ff8fee38 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/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/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-null-shard-range-isolation.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-null-shard-range-isolation.json new file mode 100644 index 000000000000..15f4af5a77d1 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-null-shard-range-isolation.json @@ -0,0 +1,15 @@ +[ + { + "description": "The malformed flag has a null shard range before a catch-all allocation. SDKs must return a parse error without poisoning the full configuration.", + "attributes": {}, + "defaultValue": "default", + "flag": "null-shard-range-flag", + "result": { + "errorCode": "PARSE_ERROR", + "reason": "ERROR", + "value": "default" + }, + "targetingKey": "alice", + "variationType": "STRING" + } +] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-null-targeting-key.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-null-targeting-key.json new file mode 100644 index 000000000000..a2226d1b21e5 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-null-targeting-key.json @@ -0,0 +1,40 @@ +[ + { + "attributes": {}, + "defaultValue": 42, + "flag": "numeric_flag", + "result": { + "reason": "STATIC", + "value": 3.1415926 + }, + "targetingKey": null, + "variationType": "NUMERIC" + }, + { + "attributes": { + "country": "France" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "ERROR", + "value": "default" + }, + "targetingKey": null, + "variationType": "STRING" + }, + { + "attributes": { + "country": "France", + "email": "null@mycompany.com" + }, + "defaultValue": "default", + "flag": "new-user-onboarding", + "result": { + "reason": "TARGETING_MATCH", + "value": "green" + }, + "targetingKey": null, + "variationType": "STRING" + } +] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-numeric-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-numeric-flag.json new file mode 100644 index 000000000000..cc52dcdff4d9 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/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/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-numeric-one-of-default.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-numeric-one-of-default.json new file mode 100644 index 000000000000..d8a7e8ba092c --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-numeric-one-of-default.json @@ -0,0 +1,13 @@ +[ + { + "attributes": {}, + "defaultValue": 0, + "flag": "numeric-one-of", + "result": { + "reason": "DEFAULT", + "value": 0 + }, + "targetingKey": "race-default", + "variationType": "INTEGER" + } +] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-numeric-one-of.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-numeric-one-of.json new file mode 100644 index 000000000000..bfa957335d3a --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/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/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-of-7-empty-targeting-key.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-of-7-empty-targeting-key.json new file mode 100644 index 000000000000..e99a207b6da7 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/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/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-regex-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-regex-flag.json new file mode 100644 index 000000000000..13ea0c3ce3bf --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-regex-flag.json @@ -0,0 +1,83 @@ +[ + { + "attributes": { + "email": "user.name+tag@capture.example" + }, + "defaultValue": "none", + "flag": "regex-flag", + "result": { + "reason": "TARGETING_MATCH", + "value": "capturing-groups" + }, + "targetingKey": "capture", + "variationType": "STRING" + }, + { + "attributes": { + "email": "llega mañana temprano" + }, + "defaultValue": "none", + "flag": "regex-flag", + "result": { + "reason": "TARGETING_MATCH", + "value": "unicode-word-boundary" + }, + "targetingKey": "unicode", + "variationType": "STRING" + }, + { + "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/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-semver-comparison-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-semver-comparison-flag.json new file mode 100644 index 000000000000..bc6fe8b92bc0 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-semver-comparison-flag.json @@ -0,0 +1,169 @@ +[ + { + "attributes": { + "app_version": "1.2.3-alpha.4" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "legacy" + }, + "targetingKey": "alice", + "variationType": "STRING" + }, + { + "attributes": { + "app_version": "1.2.3-alpha.5" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "legacy" + }, + "targetingKey": "bob", + "variationType": "STRING" + }, + { + "attributes": { + "app_version": "2.3.4" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "stable" + }, + "targetingKey": "carol", + "variationType": "STRING" + }, + { + "attributes": { + "app_version": "2.9.1" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "stable" + }, + "targetingKey": "dave", + "variationType": "STRING" + }, + { + "attributes": { + "app_version": "3.4.5-beta.1" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "stable" + }, + "targetingKey": "eve", + "variationType": "STRING" + }, + { + "attributes": { + "app_version": "3.4.5-beta.2" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "beta" + }, + "targetingKey": "frank", + "variationType": "STRING" + }, + { + "attributes": { + "app_version": "4.5.6-rc.0" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "beta" + }, + "targetingKey": "grace", + "variationType": "STRING" + }, + { + "attributes": { + "app_version": "4.5.6-rc.1" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "launch" + }, + "targetingKey": "henry", + "variationType": "STRING" + }, + { + "attributes": { + "app_version": "4.5.6-rc.1+build.42" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "launch" + }, + "targetingKey": "mia", + "variationType": "STRING" + }, + { + "attributes": { + "app_version": "4.5.6" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "future" + }, + "targetingKey": "iris", + "variationType": "STRING" + }, + { + "attributes": { + "app_version": "5.6.7" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "DEFAULT", + "value": "unknown" + }, + "targetingKey": "jane", + "variationType": "STRING" + }, + { + "attributes": { + "app_version": "not-a-semver" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "DEFAULT", + "value": "unknown" + }, + "targetingKey": "kyle", + "variationType": "STRING" + }, + { + "attributes": {}, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "DEFAULT", + "value": "unknown" + }, + "targetingKey": "liam", + "variationType": "STRING" + } +] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-semver-validation-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-semver-validation-flag.json new file mode 100644 index 000000000000..9fa90622c0c0 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-semver-validation-flag.json @@ -0,0 +1,129 @@ +[ + { + "description": "The maximum safe integer value is valid in every core version component.", + "attributes": { + "app_version": "9007199254740991.9007199254740991.9007199254740991" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "TARGETING_MATCH", + "value": "maximum" + }, + "targetingKey": "max-core", + "variationType": "STRING" + }, + { + "description": "Semver requires all three core components.", + "attributes": { + "app_version": "1.2" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "DEFAULT", + "value": "unknown" + }, + "targetingKey": "short-version", + "variationType": "STRING" + }, + { + "description": "Semver does not accept a v prefix.", + "attributes": { + "app_version": "v1.2.3" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "DEFAULT", + "value": "unknown" + }, + "targetingKey": "v-prefix", + "variationType": "STRING" + }, + { + "description": "Core numeric components cannot have leading zeros.", + "attributes": { + "app_version": "01.2.3" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "DEFAULT", + "value": "unknown" + }, + "targetingKey": "core-leading-zero", + "variationType": "STRING" + }, + { + "description": "Numeric prerelease identifiers cannot have leading zeros.", + "attributes": { + "app_version": "1.2.3-01" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "DEFAULT", + "value": "unknown" + }, + "targetingKey": "prerelease-leading-zero", + "variationType": "STRING" + }, + { + "description": "Prerelease identifiers cannot be empty.", + "attributes": { + "app_version": "1.2.3-alpha..1" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "DEFAULT", + "value": "unknown" + }, + "targetingKey": "empty-prerelease-identifier", + "variationType": "STRING" + }, + { + "description": "Build metadata identifiers cannot be empty.", + "attributes": { + "app_version": "1.2.3+build..1" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "DEFAULT", + "value": "unknown" + }, + "targetingKey": "empty-build-identifier", + "variationType": "STRING" + }, + { + "description": "Prerelease and build identifiers are ASCII-only.", + "attributes": { + "app_version": "1.2.3-α" + }, + "defaultValue": "unknown", + "flag": "semver-comparison-test", + "result": { + "reason": "DEFAULT", + "value": "unknown" + }, + "targetingKey": "non-ascii-prerelease", + "variationType": "STRING" + }, + { + "description": "A flag with an invalid configured SemVer comparand returns a parse error while the rest of the configuration remains usable.", + "attributes": { + "app_version": "1.2.3" + }, + "defaultValue": "unknown", + "flag": "semver-invalid-comparand-test", + "result": { + "errorCode": "PARSE_ERROR", + "reason": "ERROR", + "value": "unknown" + }, + "targetingKey": "invalid-comparand", + "variationType": "STRING" + } +] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-start-and-end-date-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-start-and-end-date-flag.json new file mode 100644 index 000000000000..53bf8859cdd3 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/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": "DEFAULT", + "value": "current" + }, + "targetingKey": "alice", + "variationType": "STRING" + }, + { + "attributes": { + "country": "Canada", + "version": "0.20.1" + }, + "defaultValue": "unknown", + "flag": "start-and-end-date-test", + "result": { + "reason": "DEFAULT", + "value": "current" + }, + "targetingKey": "bob", + "variationType": "STRING" + }, + { + "attributes": { + "version": "2.1.13" + }, + "defaultValue": "unknown", + "flag": "start-and-end-date-test", + "result": { + "reason": "DEFAULT", + "value": "current" + }, + "targetingKey": "charlie", + "variationType": "STRING" + } +] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-unknown-fields-tolerance.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-unknown-fields-tolerance.json new file mode 100644 index 000000000000..1bc2c9145343 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-unknown-fields-tolerance.json @@ -0,0 +1,16 @@ +[ + { + "description": "The flag and surrounding UFC config include unknown object fields that SDKs must ignore while evaluating the known schema fields.", + "attributes": { + "country": "US" + }, + "defaultValue": "default", + "flag": "unknown-fields-tolerance-flag", + "result": { + "reason": "TARGETING_MATCH", + "value": "on" + }, + "targetingKey": "alice", + "variationType": "STRING" + } +] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-unknown-operator-isolation.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-unknown-operator-isolation.json new file mode 100644 index 000000000000..c37fde4d573a --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-unknown-operator-isolation.json @@ -0,0 +1,31 @@ +[ + { + "description": "The first allocation uses an unknown operator and the second is a catch-all trap. SDKs must return a parse error without falling through to the catch-all allocation.", + "attributes": { + "country": "US" + }, + "defaultValue": "default", + "flag": "operator-grease-flag", + "result": { + "errorCode": "PARSE_ERROR", + "reason": "ERROR", + "value": "default" + }, + "targetingKey": "alice", + "variationType": "STRING" + }, + { + "description": "A valid flag in the same config must still evaluate after the unknown-operator flag is skipped.", + "attributes": { + "country": "US" + }, + "defaultValue": "default", + "flag": "valid-flag-after-invalid-config", + "result": { + "reason": "STATIC", + "value": "expected" + }, + "targetingKey": "alice", + "variationType": "STRING" + } +] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-variant-type-mismatch.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-variant-type-mismatch.json new file mode 100644 index 000000000000..ca3b775ad610 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-case-variant-type-mismatch.json @@ -0,0 +1,27 @@ +[ + { + "description": "A flag whose variation violates its declared type returns a parse error while the rest of the configuration remains usable.", + "attributes": {}, + "defaultValue": 0, + "flag": "variant-type-mismatch-flag", + "result": { + "errorCode": "PARSE_ERROR", + "reason": "ERROR", + "value": 0 + }, + "targetingKey": "user-1", + "variationType": "INTEGER" + }, + { + "description": "A valid flag in the same configuration continues to evaluate when a malformed neighboring flag returns a parse error.", + "attributes": {}, + "defaultValue": "default", + "flag": "valid-flag-after-invalid-config", + "result": { + "reason": "STATIC", + "value": "expected" + }, + "targetingKey": "valid-neighbor", + "variationType": "STRING" + } +] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-flag-that-does-not-exist.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-flag-that-does-not-exist.json new file mode 100644 index 000000000000..0be74f1f7ac6 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-flag-that-does-not-exist.json @@ -0,0 +1,46 @@ +[ + { + "attributes": { + "country": "US", + "email": "alice@mycompany.com" + }, + "defaultValue": 0, + "flag": "flag-that-does-not-exist", + "result": { + "errorCode": "FLAG_NOT_FOUND", + "reason": "ERROR", + "value": 0 + }, + "targetingKey": "alice", + "variationType": "NUMERIC" + }, + { + "attributes": { + "country": "Canada", + "email": "bob@example.com" + }, + "defaultValue": 0, + "flag": "flag-that-does-not-exist", + "result": { + "errorCode": "FLAG_NOT_FOUND", + "reason": "ERROR", + "value": 0 + }, + "targetingKey": "bob", + "variationType": "NUMERIC" + }, + { + "attributes": { + "age": 50 + }, + "defaultValue": 0, + "flag": "flag-that-does-not-exist", + "result": { + "errorCode": "FLAG_NOT_FOUND", + "reason": "ERROR", + "value": 0 + }, + "targetingKey": "charlie", + "variationType": "NUMERIC" + } +] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-json-config-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-json-config-flag.json new file mode 100644 index 000000000000..45a9c2ee9735 --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/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.0, + "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.0, + "integer": 2, + "string": "two" + } + }, + "targetingKey": "bob", + "variationType": "JSON" + }, + { + "attributes": { + "age": 50 + }, + "defaultValue": { + "foo": "bar" + }, + "flag": "json-config-flag", + "result": { + "reason": "SPLIT", + "value": { + "float": 2.0, + "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/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-no-allocations-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-no-allocations-flag.json similarity index 70% rename from tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-no-allocations-flag.json rename to tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-no-allocations-flag.json index 45867e5897cf..2b03b9a39a19 100644 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-no-allocations-flag.json +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-no-allocations-flag.json @@ -1,52 +1,55 @@ [ { - "flag": "no_allocations_flag", - "variationType": "JSON", + "attributes": { + "country": "US", + "email": "alice@mycompany.com" + }, "defaultValue": { "message": "Hello, world!" }, - "targetingKey": "alice", - "attributes": { - "email": "alice@mycompany.com", - "country": "US" - }, + "flag": "no_allocations_flag", "result": { + "reason": "DEFAULT", "value": { "message": "Hello, world!" } - } + }, + "targetingKey": "alice", + "variationType": "JSON" }, { - "flag": "no_allocations_flag", - "variationType": "JSON", + "attributes": { + "country": "Canada", + "email": "bob@example.com" + }, "defaultValue": { "message": "Hello, world!" }, - "targetingKey": "bob", - "attributes": { - "email": "bob@example.com", - "country": "Canada" - }, + "flag": "no_allocations_flag", "result": { + "reason": "DEFAULT", "value": { "message": "Hello, world!" } - } + }, + "targetingKey": "bob", + "variationType": "JSON" }, { - "flag": "no_allocations_flag", - "variationType": "JSON", - "defaultValue": { - "message": "Hello, world!" - }, - "targetingKey": "charlie", "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/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-special-characters.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-special-characters.json similarity index 52% rename from tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-special-characters.json rename to tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-special-characters.json index 59ef5cbe87d7..1ed7795bb95c 100644 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-special-characters.json +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-special-characters.json @@ -1,78 +1,58 @@ [ { - "flag": "special-characters", - "variationType": "JSON", - "defaultValue": {}, - "targetingKey": "ash", "attributes": {}, + "defaultValue": {}, + "flag": "special-characters", "result": { + "reason": "SPLIT", "value": { "a": "kümmert", "b": "schön" - }, - "variant": "de", - "flagMetadata": { - "allocationKey": "allocation-test", - "variationType": "object", - "doLog": true } - } + }, + "targetingKey": "ash", + "variationType": "JSON" }, { - "flag": "special-characters", - "variationType": "JSON", - "defaultValue": {}, - "targetingKey": "ben", "attributes": {}, + "defaultValue": {}, + "flag": "special-characters", "result": { + "reason": "SPLIT", "value": { "a": "піклуватися", "b": "любов" - }, - "variant": "ua", - "flagMetadata": { - "allocationKey": "allocation-test", - "variationType": "object", - "doLog": true } - } + }, + "targetingKey": "ben", + "variationType": "JSON" }, { - "flag": "special-characters", - "variationType": "JSON", - "defaultValue": {}, - "targetingKey": "cameron", "attributes": {}, + "defaultValue": {}, + "flag": "special-characters", "result": { + "reason": "SPLIT", "value": { "a": "照顾", "b": "漂亮" - }, - "variant": "zh", - "flagMetadata": { - "allocationKey": "allocation-test", - "variationType": "object", - "doLog": true } - } + }, + "targetingKey": "cameron", + "variationType": "JSON" }, { - "flag": "special-characters", - "variationType": "JSON", - "defaultValue": {}, - "targetingKey": "darryl", "attributes": {}, + "defaultValue": {}, + "flag": "special-characters", "result": { + "reason": "SPLIT", "value": { "a": "🤗", "b": "🌸" - }, - "variant": "emoji", - "flagMetadata": { - "allocationKey": "allocation-test", - "variationType": "object", - "doLog": true } - } + }, + "targetingKey": "darryl", + "variationType": "JSON" } ] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-string-with-special-characters.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/evaluation-cases/test-string-with-special-characters.json new file mode 100644 index 000000000000..32397a48398a --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/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/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/ufc-config.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/ufc-config.json new file mode 100644 index 000000000000..52fd31d5ff1a --- /dev/null +++ b/tracer/test/Datadog.Trace.Tests/FeatureFlags/ffe-system-test-data/ufc-config.json @@ -0,0 +1,4146 @@ +{ + "createdAt": "2024-04-17T19:40:53.716Z", + "format": "SERVER", + "environment": { + "name": "Test", + "unknownEnvironmentField": "ignored" + }, + "unknownTopLevelField": "ignored", + "unknownTopLevelNull": null, + "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" + }, + "capturing-groups": { + "key": "capturing-groups", + "value": "capturing-groups" + }, + "unicode-word-boundary": { + "key": "unicode-word-boundary", + "value": "unicode-word-boundary" + } + }, + "allocations": [ + { + "key": "capturing-groups", + "rules": [ + { + "conditions": [ + { + "attribute": "email", + "operator": "MATCHES", + "value": "^([[:alnum:]._%+-]+)@capture\\.example$" + } + ] + } + ], + "splits": [ + { + "variationKey": "capturing-groups", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "unicode-word-boundary", + "rules": [ + { + "conditions": [ + { + "attribute": "email", + "operator": "MATCHES", + "value": "(?u)\\bmañana\\b" + } + ] + } + ], + "splits": [ + { + "variationKey": "unicode-word-boundary", + "shards": [] + } + ], + "doLog": true + }, + { + "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 + } + ] + }, + "semver-comparison-test": { + "key": "semver-comparison-test", + "enabled": true, + "variationType": "STRING", + "variations": { + "legacy": { + "key": "legacy", + "value": "legacy" + }, + "stable": { + "key": "stable", + "value": "stable" + }, + "beta": { + "key": "beta", + "value": "beta" + }, + "launch": { + "key": "launch", + "value": "launch" + }, + "future": { + "key": "future", + "value": "future" + }, + "maximum": { + "key": "maximum", + "value": "maximum" + } + }, + "allocations": [ + { + "key": "maximum-version", + "rules": [ + { + "conditions": [ + { + "attribute": "app_version", + "operator": "SEMVER_EQ", + "value": "9007199254740991.9007199254740991.9007199254740991" + } + ] + } + ], + "splits": [ + { + "variationKey": "maximum", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "legacy-versions", + "rules": [ + { + "conditions": [ + { + "attribute": "app_version", + "operator": "SEMVER_LTE", + "value": "1.2.3-alpha.4" + } + ] + }, + { + "conditions": [ + { + "attribute": "app_version", + "operator": "SEMVER_GT", + "value": "1.2.3-alpha.4" + }, + { + "attribute": "app_version", + "operator": "SEMVER_LT", + "value": "2.3.4" + } + ] + } + ], + "splits": [ + { + "variationKey": "legacy", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "stable-versions", + "rules": [ + { + "conditions": [ + { + "attribute": "app_version", + "operator": "SEMVER_GTE", + "value": "2.3.4" + }, + { + "attribute": "app_version", + "operator": "SEMVER_LT", + "value": "3.4.5-beta.2" + } + ] + } + ], + "splits": [ + { + "variationKey": "stable", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "beta-versions", + "rules": [ + { + "conditions": [ + { + "attribute": "app_version", + "operator": "SEMVER_GTE", + "value": "3.4.5-beta.2" + }, + { + "attribute": "app_version", + "operator": "SEMVER_LT", + "value": "4.5.6-rc.1" + } + ] + } + ], + "splits": [ + { + "variationKey": "beta", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "launch-version", + "rules": [ + { + "conditions": [ + { + "attribute": "app_version", + "operator": "SEMVER_EQ", + "value": "4.5.6-rc.1" + } + ] + } + ], + "splits": [ + { + "variationKey": "launch", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "future-versions", + "rules": [ + { + "conditions": [ + { + "attribute": "app_version", + "operator": "SEMVER_GT", + "value": "4.5.6-rc.1" + }, + { + "attribute": "app_version", + "operator": "SEMVER_NEQ", + "value": "5.6.7" + } + ] + } + ], + "splits": [ + { + "variationKey": "future", + "shards": [] + } + ], + "doLog": true + } + ] + }, + "semver-invalid-comparand-test": { + "key": "semver-invalid-comparand-test", + "enabled": true, + "variationType": "STRING", + "comment": "This flag deliberately uses an invalid configured SemVer comparand. SDKs must remove this flag without rejecting the full configuration.", + "variations": { + "matched": { + "key": "matched", + "value": "matched" + } + }, + "allocations": [ + { + "key": "invalid-comparand", + "rules": [ + { + "conditions": [ + { + "attribute": "app_version", + "operator": "SEMVER_EQ", + "value": "18446744073709551616.0.0" + } + ] + } + ], + "splits": [ + { + "variationKey": "matched", + "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 + } + ] + }, + "unknown-fields-tolerance-flag": { + "key": "unknown-fields-tolerance-flag", + "enabled": true, + "variationType": "STRING", + "comment": "This flag deliberately contains unknown fields at every fixed-schema UFC level. SDKs must ignore those fields and evaluate the flag normally.", + "unknownFlagField": "ignored", + "variations": { + "on": { + "key": "on", + "value": "on", + "unknownVariationField": "ignored" + } + }, + "allocations": [ + { + "key": "unknown-fields-allocation", + "unknownAllocationField": "ignored", + "rules": [ + { + "unknownRuleField": "ignored", + "conditions": [ + { + "attribute": "country", + "operator": "ONE_OF", + "value": [ + "US" + ], + "unknownConditionField": "ignored" + } + ] + } + ], + "splits": [ + { + "variationKey": "on", + "unknownSplitField": "ignored", + "shards": [ + { + "salt": "unknown-fields-tolerance-flag", + "totalShards": 10000, + "unknownShardField": "ignored", + "ranges": [ + { + "start": 0, + "end": 10000, + "unknownRangeField": "ignored" + } + ] + } + ] + } + ], + "doLog": true + } + ] + }, + "operator-grease-flag": { + "key": "operator-grease-flag", + "enabled": true, + "variationType": "STRING", + "comment": "This flag deliberately uses an unknown condition operator. SDKs must remove this flag rather than falling through to the catch-all allocation or rejecting the whole config.", + "variations": { + "trap": { + "key": "trap", + "value": "trap" + }, + "on": { + "key": "on", + "value": "on" + } + }, + "allocations": [ + { + "key": "grease-allocation", + "rules": [ + { + "conditions": [ + { + "attribute": "country", + "operator": "NOT_A_REAL_OPERATOR", + "value": "anything" + } + ] + } + ], + "splits": [ + { + "variationKey": "trap", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "default-allocation", + "rules": [], + "splits": [ + { + "variationKey": "on", + "shards": [] + } + ], + "doLog": true + } + ] + }, + "invalid-regex-flag": { + "key": "invalid-regex-flag", + "enabled": true, + "variationType": "STRING", + "comment": "This flag deliberately uses the invalid regex *@datadoghq.com. SDKs must remove this flag rather than falling through to a later allocation or rejecting the whole config.", + "variations": { + "invalid-regex-match": { + "key": "invalid-regex-match", + "value": "invalid-regex-match" + }, + "catch-all": { + "key": "catch-all", + "value": "catch-all" + } + }, + "allocations": [ + { + "key": "invalid-regex-allocation", + "rules": [ + { + "conditions": [ + { + "attribute": "email", + "operator": "MATCHES", + "value": "*@datadoghq.com" + } + ] + } + ], + "splits": [ + { + "variationKey": "invalid-regex-match", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "invalid-regex-catch-all", + "rules": [], + "splits": [ + { + "variationKey": "catch-all", + "shards": [] + } + ], + "doLog": true + } + ] + }, + "variant-type-mismatch-flag": { + "key": "variant-type-mismatch-flag", + "enabled": true, + "variationType": "INTEGER", + "comment": "This flag is intentionally invalid: one variation contains a string even though the flag declares INTEGER values. SDKs must remove this flag without rejecting the full configuration.", + "variations": { + "invalid": { + "key": "invalid", + "value": "not-an-integer" + }, + "valid": { + "key": "valid", + "value": 0 + } + }, + "allocations": [ + { + "key": "default-allocation", + "rules": [], + "splits": [ + { + "variationKey": "invalid", + "shards": [] + } + ], + "doLog": true + } + ] + }, + "invalid-gt-condition-flag": { + "key": "invalid-gt-condition-flag", + "enabled": true, + "variationType": "STRING", + "comment": "This flag deliberately gives GT a string operand. SDKs must remove this flag rather than falling through to the catch-all allocation.", + "variations": { + "trap": { + "key": "trap", + "value": "trap" + }, + "catch-all": { + "key": "catch-all", + "value": "catch-all" + } + }, + "allocations": [ + { + "key": "invalid-gt-allocation", + "rules": [ + { + "conditions": [ + { + "attribute": "age", + "operator": "GT", + "value": "not-a-number" + } + ] + } + ], + "splits": [ + { + "variationKey": "trap", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "invalid-gt-catch-all", + "rules": [], + "splits": [ + { + "variationKey": "catch-all", + "shards": [] + } + ], + "doLog": true + } + ] + }, + "invalid-one-of-condition-flag": { + "key": "invalid-one-of-condition-flag", + "enabled": true, + "variationType": "STRING", + "comment": "This flag deliberately gives ONE_OF a scalar operand. SDKs must remove this flag rather than falling through to the catch-all allocation.", + "variations": { + "trap": { + "key": "trap", + "value": "trap" + }, + "catch-all": { + "key": "catch-all", + "value": "catch-all" + } + }, + "allocations": [ + { + "key": "invalid-one-of-allocation", + "rules": [ + { + "conditions": [ + { + "attribute": "role", + "operator": "ONE_OF", + "value": "admin" + } + ] + } + ], + "splits": [ + { + "variationKey": "trap", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "invalid-one-of-catch-all", + "rules": [], + "splits": [ + { + "variationKey": "catch-all", + "shards": [] + } + ], + "doLog": true + } + ] + }, + "invalid-is-null-condition-flag": { + "key": "invalid-is-null-condition-flag", + "enabled": true, + "variationType": "STRING", + "comment": "This flag deliberately gives IS_NULL a non-boolean operand. SDKs must remove this flag rather than falling through to the catch-all allocation.", + "variations": { + "trap": { + "key": "trap", + "value": "trap" + }, + "catch-all": { + "key": "catch-all", + "value": "catch-all" + } + }, + "allocations": [ + { + "key": "invalid-is-null-allocation", + "rules": [ + { + "conditions": [ + { + "attribute": "deleted_at", + "operator": "IS_NULL", + "value": "not-a-boolean" + } + ] + } + ], + "splits": [ + { + "variationKey": "trap", + "shards": [] + } + ], + "doLog": true + }, + { + "key": "invalid-is-null-catch-all", + "rules": [], + "splits": [ + { + "variationKey": "catch-all", + "shards": [] + } + ], + "doLog": true + } + ] + }, + "malformed-allocations-flag": { + "key": "malformed-allocations-flag", + "enabled": true, + "variationType": "STRING", + "comment": "This flag is intentionally UFC-schema-invalid: allocations must be an array. SDKs must remove this flag without rejecting the full configuration.", + "variations": { + "on": { + "key": "on", + "value": "on" + } + }, + "allocations": "this-is-not-a-list" + }, + "missing-split-shards-flag": { + "key": "missing-split-shards-flag", + "enabled": true, + "variationType": "STRING", + "comment": "This flag is intentionally UFC-schema-invalid: split.shards is required even when the intended split is unsharded. SDKs must treat omitted shards differently from an explicit empty shards array.", + "variations": { + "trap": { + "key": "trap", + "value": "trap" + } + }, + "allocations": [ + { + "key": "malformed-split-allocation", + "rules": [], + "splits": [ + { + "variationKey": "trap" + } + ], + "doLog": true + } + ] + }, + "overflow-total-shards-flag": { + "key": "overflow-total-shards-flag", + "enabled": true, + "variationType": "STRING", + "comment": "This flag is intentionally UFC-schema-invalid: split.shards[].totalShards must fit in an unsigned 32-bit integer. SDKs must remove this flag rather than overflowing or poisoning the whole config.", + "variations": { + "trap": { + "key": "trap", + "value": "trap" + } + }, + "allocations": [ + { + "key": "malformed-shard-allocation", + "rules": [], + "splits": [ + { + "variationKey": "trap", + "shards": [ + { + "salt": "overflow-total-shards-flag", + "totalShards": 4294967296, + "ranges": [ + { + "start": 0, + "end": 1 + } + ] + } + ] + } + ], + "doLog": true + } + ] + }, + "negative-shard-range-start-flag": { + "key": "negative-shard-range-start-flag", + "enabled": true, + "variationType": "STRING", + "comment": "This flag is intentionally UFC-schema-invalid: split.shards[].ranges[].start must be an unsigned integer. SDKs must remove this flag rather than treating a negative range as matching traffic.", + "variations": { + "trap": { + "key": "trap", + "value": "trap" + } + }, + "allocations": [ + { + "key": "malformed-shard-allocation", + "rules": [], + "splits": [ + { + "variationKey": "trap", + "shards": [ + { + "salt": "negative-shard-range-start-flag", + "totalShards": 100, + "ranges": [ + { + "start": -1, + "end": 1 + } + ] + } + ] + } + ], + "doLog": true + } + ] + }, + "null-shard-range-flag": { + "key": "null-shard-range-flag", + "enabled": true, + "variationType": "STRING", + "comment": "This flag is intentionally UFC-schema-invalid: split.shards[].ranges[] contains null. SDKs must remove this flag rather than panicking or poisoning the whole config.", + "variations": { + "trap": { + "key": "trap", + "value": "trap" + }, + "catch-all": { + "key": "catch-all", + "value": "catch-all" + } + }, + "allocations": [ + { + "key": "null-shard-range-allocation", + "rules": [], + "splits": [ + { + "variationKey": "trap", + "shards": [ + { + "salt": "null-shard-range-flag", + "totalShards": 8192, + "ranges": [ + null + ] + } + ] + } + ], + "doLog": true + }, + { + "key": "null-shard-range-catch-all", + "rules": [], + "splits": [ + { + "variationKey": "catch-all", + "shards": [] + } + ], + "doLog": true + } + ] + }, + "valid-flag-after-invalid-config": { + "key": "valid-flag-after-invalid-config", + "enabled": true, + "variationType": "STRING", + "comment": "This valid neighbor proves malformed or unsupported flags do not poison the rest of the remote config.", + "variations": { + "expected": { + "key": "expected", + "value": "expected" + } + }, + "allocations": [ + { + "key": "default-allocation", + "rules": [], + "splits": [ + { + "variationKey": "expected", + "shards": [] + } + ], + "doLog": true + } + ] + } + } +} diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/config/flags-v1.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/config/flags-v1.json deleted file mode 100644 index 5b21a9f36615..000000000000 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/config/flags-v1.json +++ /dev/null @@ -1,2953 +0,0 @@ -{ - "data": { - "type": "universal-flag-configuration", - "id": "1", - "attributes": { - "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 - } - ] - }, - "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 - } - ] - } - } - } - } -} diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-flag-with-empty-string.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-flag-with-empty-string.json deleted file mode 100644 index 32a1c1febb7b..000000000000 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-flag-with-empty-string.json +++ /dev/null @@ -1,36 +0,0 @@ -[ - { - "flag": "empty_string_flag", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "alice", - "attributes": { - "country": "US" - }, - "result": { - "value": "", - "variant": "empty_string", - "flagMetadata": { - "allocationKey": "allocation-empty", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "empty_string_flag", - "variationType": "STRING", - "defaultValue": "default", - "targetingKey": "bob", - "attributes": {}, - "result": { - "value": "non_empty", - "variant": "non_empty", - "flagMetadata": { - "allocationKey": "allocation-test", - "variationType": "string", - "doLog": true - } - } - } -] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-integer-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-integer-flag.json deleted file mode 100644 index 4a41d042f628..000000000000 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-integer-flag.json +++ /dev/null @@ -1,382 +0,0 @@ -[ - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "alice", - "attributes": { - "email": "alice@mycompany.com", - "country": "US" - }, - "result": { - "value": 3, - "variant": "three", - "flagMetadata": { - "allocationKey": "targeted allocation", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "bob", - "attributes": { - "email": "bob@example.com", - "country": "Canada" - }, - "result": { - "value": 3, - "variant": "three", - "flagMetadata": { - "allocationKey": "targeted allocation", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "charlie", - "attributes": { - "age": 50 - }, - "result": { - "value": 2, - "variant": "two", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "debra", - "attributes": { - "email": "test@test.com", - "country": "Mexico", - "age": 25 - }, - "result": { - "value": 3, - "variant": "three", - "flagMetadata": { - "allocationKey": "targeted allocation", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "1", - "attributes": {}, - "result": { - "value": 2, - "variant": "two", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "2", - "attributes": {}, - "result": { - "value": 2, - "variant": "two", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "3", - "attributes": {}, - "result": { - "value": 2, - "variant": "two", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "4", - "attributes": {}, - "result": { - "value": 2, - "variant": "two", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "5", - "attributes": {}, - "result": { - "value": 1, - "variant": "one", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "6", - "attributes": {}, - "result": { - "value": 2, - "variant": "two", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "7", - "attributes": {}, - "result": { - "value": 1, - "variant": "one", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "8", - "attributes": {}, - "result": { - "value": 1, - "variant": "one", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "9", - "attributes": {}, - "result": { - "value": 2, - "variant": "two", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "10", - "attributes": {}, - "result": { - "value": 2, - "variant": "two", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "11", - "attributes": {}, - "result": { - "value": 1, - "variant": "one", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "12", - "attributes": {}, - "result": { - "value": 1, - "variant": "one", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "13", - "attributes": {}, - "result": { - "value": 2, - "variant": "two", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "14", - "attributes": {}, - "result": { - "value": 1, - "variant": "one", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "15", - "attributes": {}, - "result": { - "value": 2, - "variant": "two", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "16", - "attributes": {}, - "result": { - "value": 2, - "variant": "two", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "17", - "attributes": {}, - "result": { - "value": 1, - "variant": "one", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "18", - "attributes": {}, - "result": { - "value": 1, - "variant": "one", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "integer-flag", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "19", - "attributes": {}, - "result": { - "value": 1, - "variant": "one", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "number", - "doLog": true - } - } - } -] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-kill-switch-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-kill-switch-flag.json deleted file mode 100644 index 29e65ba5bb41..000000000000 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-kill-switch-flag.json +++ /dev/null @@ -1,434 +0,0 @@ -[ - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "alice", - "attributes": { - "email": "alice@mycompany.com", - "country": "US" - }, - "result": { - "value": true, - "variant": "on", - "flagMetadata": { - "allocationKey": "on-for-NA", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "bob", - "attributes": { - "email": "bob@example.com", - "country": "Canada" - }, - "result": { - "value": true, - "variant": "on", - "flagMetadata": { - "allocationKey": "on-for-NA", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "barbara", - "attributes": { - "email": "barbara@example.com", - "country": "canada" - }, - "result": { - "value": false, - "variant": "off", - "flagMetadata": { - "allocationKey": "off-for-all", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "charlie", - "attributes": { - "age": 40 - }, - "result": { - "value": false, - "variant": "off", - "flagMetadata": { - "allocationKey": "off-for-all", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "debra", - "attributes": { - "email": "test@test.com", - "country": "Mexico", - "age": 25 - }, - "result": { - "value": true, - "variant": "on", - "flagMetadata": { - "allocationKey": "on-for-NA", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "1", - "attributes": {}, - "result": { - "value": false, - "variant": "off", - "flagMetadata": { - "allocationKey": "off-for-all", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "2", - "attributes": { - "country": "Mexico" - }, - "result": { - "value": true, - "variant": "on", - "flagMetadata": { - "allocationKey": "on-for-NA", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "3", - "attributes": { - "country": "UK", - "age": 50 - }, - "result": { - "value": true, - "variant": "on", - "flagMetadata": { - "allocationKey": "on-for-age-50+", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "4", - "attributes": { - "country": "Germany" - }, - "result": { - "value": false, - "variant": "off", - "flagMetadata": { - "allocationKey": "off-for-all", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "5", - "attributes": { - "country": "Germany" - }, - "result": { - "value": false, - "variant": "off", - "flagMetadata": { - "allocationKey": "off-for-all", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "6", - "attributes": { - "country": "Germany" - }, - "result": { - "value": false, - "variant": "off", - "flagMetadata": { - "allocationKey": "off-for-all", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "7", - "attributes": { - "country": "US", - "age": 12 - }, - "result": { - "value": true, - "variant": "on", - "flagMetadata": { - "allocationKey": "on-for-NA", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "8", - "attributes": { - "country": "Italy", - "age": 60 - }, - "result": { - "value": true, - "variant": "on", - "flagMetadata": { - "allocationKey": "on-for-age-50+", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "9", - "attributes": { - "email": "email@email.com" - }, - "result": { - "value": false, - "variant": "off", - "flagMetadata": { - "allocationKey": "off-for-all", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "10", - "attributes": {}, - "result": { - "value": false, - "variant": "off", - "flagMetadata": { - "allocationKey": "off-for-all", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "11", - "attributes": {}, - "result": { - "value": false, - "variant": "off", - "flagMetadata": { - "allocationKey": "off-for-all", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "12", - "attributes": { - "country": "US" - }, - "result": { - "value": true, - "variant": "on", - "flagMetadata": { - "allocationKey": "on-for-NA", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "13", - "attributes": { - "country": "Canada" - }, - "result": { - "value": true, - "variant": "on", - "flagMetadata": { - "allocationKey": "on-for-NA", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "14", - "attributes": {}, - "result": { - "value": false, - "variant": "off", - "flagMetadata": { - "allocationKey": "off-for-all", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "15", - "attributes": { - "country": "Denmark" - }, - "result": { - "value": false, - "variant": "off", - "flagMetadata": { - "allocationKey": "off-for-all", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "16", - "attributes": { - "country": "Norway" - }, - "result": { - "value": false, - "variant": "off", - "flagMetadata": { - "allocationKey": "off-for-all", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "17", - "attributes": { - "country": "UK" - }, - "result": { - "value": false, - "variant": "off", - "flagMetadata": { - "allocationKey": "off-for-all", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "18", - "attributes": { - "country": "UK" - }, - "result": { - "value": false, - "variant": "off", - "flagMetadata": { - "allocationKey": "off-for-all", - "variationType": "boolean", - "doLog": true - } - } - }, - { - "flag": "kill-switch", - "variationType": "BOOLEAN", - "defaultValue": false, - "targetingKey": "19", - "attributes": { - "country": "UK" - }, - "result": { - "value": false, - "variant": "off", - "flagMetadata": { - "allocationKey": "off-for-all", - "variationType": "boolean", - "doLog": true - } - } - } -] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-microsecond-date-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-microsecond-date-flag.json deleted file mode 100644 index d363b260c42d..000000000000 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-microsecond-date-flag.json +++ /dev/null @@ -1,54 +0,0 @@ -[ - { - "flag": "microsecond-date-test", - "variationType": "STRING", - "defaultValue": "unknown", - "targetingKey": "alice", - "attributes": {}, - "result": { - "value": "active", - "variant": "active", - "flagMetadata": { - "allocationKey": "active-allocation", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "microsecond-date-test", - "variationType": "STRING", - "defaultValue": "unknown", - "targetingKey": "bob", - "attributes": { - "country": "US" - }, - "result": { - "value": "active", - "variant": "active", - "flagMetadata": { - "allocationKey": "active-allocation", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "microsecond-date-test", - "variationType": "STRING", - "defaultValue": "unknown", - "targetingKey": "charlie", - "attributes": { - "version": "1.0.0" - }, - "result": { - "value": "active", - "variant": "active", - "flagMetadata": { - "allocationKey": "active-allocation", - "variationType": "string", - "doLog": true - } - } - } -] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-null-operator-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-null-operator-flag.json deleted file mode 100644 index dd5c687b893c..000000000000 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-null-operator-flag.json +++ /dev/null @@ -1,94 +0,0 @@ -[ - { - "flag": "null-operator-test", - "variationType": "STRING", - "defaultValue": "default-null", - "targetingKey": "alice", - "attributes": { - "size": 5, - "country": "US" - }, - "result": { - "value": "old", - "variant": "old", - "flagMetadata": { - "allocationKey": "null-operator", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "null-operator-test", - "variationType": "STRING", - "defaultValue": "default-null", - "targetingKey": "bob", - "attributes": { - "size": 10, - "country": "Canada" - }, - "result": { - "value": "new", - "variant": "new", - "flagMetadata": { - "allocationKey": "not-null-operator", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "null-operator-test", - "variationType": "STRING", - "defaultValue": "default-null", - "targetingKey": "charlie", - "attributes": { - "size": null - }, - "result": { - "value": "old", - "variant": "old", - "flagMetadata": { - "allocationKey": "null-operator", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "null-operator-test", - "variationType": "STRING", - "defaultValue": "default-null", - "targetingKey": "david", - "attributes": { - "size": 26 - }, - "result": { - "value": "new", - "variant": "new", - "flagMetadata": { - "allocationKey": "not-null-operator", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "null-operator-test", - "variationType": "STRING", - "defaultValue": "default-null", - "targetingKey": "elize", - "attributes": { - "country": "UK" - }, - "result": { - "value": "old", - "variant": "old", - "flagMetadata": { - "allocationKey": "null-operator", - "variationType": "string", - "doLog": true - } - } - } -] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-numeric-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-numeric-flag.json deleted file mode 100644 index 0e6ed8b1b3a3..000000000000 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-numeric-flag.json +++ /dev/null @@ -1,58 +0,0 @@ -[ - { - "flag": "numeric_flag", - "variationType": "NUMERIC", - "defaultValue": 0.0, - "targetingKey": "alice", - "attributes": { - "email": "alice@mycompany.com", - "country": "US" - }, - "result": { - "value": 3.1415926, - "variant": "pi", - "flagMetadata": { - "allocationKey": "rollout", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "numeric_flag", - "variationType": "NUMERIC", - "defaultValue": 0.0, - "targetingKey": "bob", - "attributes": { - "email": "bob@example.com", - "country": "Canada" - }, - "result": { - "value": 3.1415926, - "variant": "pi", - "flagMetadata": { - "allocationKey": "rollout", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "numeric_flag", - "variationType": "NUMERIC", - "defaultValue": 0.0, - "targetingKey": "charlie", - "attributes": { - "age": 50 - }, - "result": { - "value": 3.1415926, - "variant": "pi", - "flagMetadata": { - "allocationKey": "rollout", - "variationType": "number", - "doLog": true - } - } - } -] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-numeric-one-of.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-numeric-one-of.json deleted file mode 100644 index 5ab68af5196e..000000000000 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-numeric-one-of.json +++ /dev/null @@ -1,122 +0,0 @@ -[ - { - "flag": "numeric-one-of", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "alice", - "attributes": { - "number": 1 - }, - "result": { - "value": 1, - "variant": "1", - "flagMetadata": { - "allocationKey": "1-for-1", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "numeric-one-of", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "bob", - "attributes": { - "number": 2 - }, - "result": { - "value": 0 - } - }, - { - "flag": "numeric-one-of", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "charlie", - "attributes": { - "number": 3 - }, - "result": { - "value": 3, - "variant": "3", - "flagMetadata": { - "allocationKey": "3-for-not-2", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "numeric-one-of", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "derek", - "attributes": { - "number": 4 - }, - "result": { - "value": 3, - "variant": "3", - "flagMetadata": { - "allocationKey": "3-for-not-2", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "numeric-one-of", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "erica", - "attributes": { - "number": "1" - }, - "result": { - "value": 1, - "variant": "1", - "flagMetadata": { - "allocationKey": "1-for-1", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "numeric-one-of", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "frank", - "attributes": { - "number": 1 - }, - "result": { - "value": 1, - "variant": "1", - "flagMetadata": { - "allocationKey": "1-for-1", - "variationType": "number", - "doLog": true - } - } - }, - { - "flag": "numeric-one-of", - "variationType": "INTEGER", - "defaultValue": 0, - "targetingKey": "george", - "attributes": { - "number": 123456789 - }, - "result": { - "value": 2, - "variant": "2", - "flagMetadata": { - "allocationKey": "2-for-123456789", - "variationType": "number", - "doLog": true - } - } - } -] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-race-conditions.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-race-conditions.json deleted file mode 100644 index fa940c843b42..000000000000 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-race-conditions.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "flag": "numeric-one-of", - "variationType": "INTEGER", - "defaultValue": 0, - "result": { - "value": 0 - } - } -] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-regex-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-regex-flag.json deleted file mode 100644 index 952a37aabcfa..000000000000 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-regex-flag.json +++ /dev/null @@ -1,65 +0,0 @@ -[ - { - "flag": "regex-flag", - "variationType": "STRING", - "defaultValue": "none", - "targetingKey": "alice", - "attributes": { - "version": "1.15.0", - "email": "alice@example.com" - }, - "result": { - "value": "partial-example", - "variant": "partial-example", - "flagMetadata": { - "allocationKey": "partial-example", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "regex-flag", - "variationType": "STRING", - "defaultValue": "none", - "targetingKey": "bob", - "attributes": { - "version": "0.20.1", - "email": "bob@test.com" - }, - "result": { - "value": "test", - "variant": "test", - "flagMetadata": { - "allocationKey": "test", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "regex-flag", - "variationType": "STRING", - "defaultValue": "none", - "targetingKey": "charlie", - "attributes": { - "version": "2.1.13" - }, - "result": { - "value": "none" - } - }, - { - "flag": "regex-flag", - "variationType": "STRING", - "defaultValue": "none", - "targetingKey": "derek", - "attributes": { - "version": "2.1.13", - "email": "derek@gmail.com" - }, - "result": { - "value": "none" - } - } -] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-start-and-end-date-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-start-and-end-date-flag.json deleted file mode 100644 index caf805d14325..000000000000 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-case-start-and-end-date-flag.json +++ /dev/null @@ -1,58 +0,0 @@ -[ - { - "flag": "start-and-end-date-test", - "variationType": "STRING", - "defaultValue": "unknown", - "targetingKey": "alice", - "attributes": { - "version": "1.15.0", - "country": "US" - }, - "result": { - "value": "current", - "variant": "current", - "flagMetadata": { - "allocationKey": "current-versions", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "start-and-end-date-test", - "variationType": "STRING", - "defaultValue": "unknown", - "targetingKey": "bob", - "attributes": { - "version": "0.20.1", - "country": "Canada" - }, - "result": { - "value": "current", - "variant": "current", - "flagMetadata": { - "allocationKey": "current-versions", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "start-and-end-date-test", - "variationType": "STRING", - "defaultValue": "unknown", - "targetingKey": "charlie", - "attributes": { - "version": "2.1.13" - }, - "result": { - "value": "current", - "variant": "current", - "flagMetadata": { - "allocationKey": "current-versions", - "variationType": "string", - "doLog": true - } - } - } -] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-flag-that-does-not-exist.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-flag-that-does-not-exist.json deleted file mode 100644 index 7499bba1c506..000000000000 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-flag-that-does-not-exist.json +++ /dev/null @@ -1,40 +0,0 @@ -[ - { - "flag": "flag-that-does-not-exist", - "variationType": "NUMERIC", - "defaultValue": 0.0, - "targetingKey": "alice", - "attributes": { - "email": "alice@mycompany.com", - "country": "US" - }, - "result": { - "value": 0.0 - } - }, - { - "flag": "flag-that-does-not-exist", - "variationType": "NUMERIC", - "defaultValue": 0.0, - "targetingKey": "bob", - "attributes": { - "email": "bob@example.com", - "country": "Canada" - }, - "result": { - "value": 0.0 - } - }, - { - "flag": "flag-that-does-not-exist", - "variationType": "NUMERIC", - "defaultValue": 0.0, - "targetingKey": "charlie", - "attributes": { - "age": 50 - }, - "result": { - "value": 0.0 - } - } -] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-json-config-flag.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-json-config-flag.json deleted file mode 100644 index 3d4478ff7118..000000000000 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-json-config-flag.json +++ /dev/null @@ -1,96 +0,0 @@ -[ - { - "flag": "json-config-flag", - "variationType": "JSON", - "defaultValue": { - "foo": "bar" - }, - "targetingKey": "alice", - "attributes": { - "email": "alice@mycompany.com", - "country": "US" - }, - "result": { - "value": { - "integer": 1, - "string": "one", - "float": 1.0 - }, - "variant": "one", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "object", - "doLog": true - } - } - }, - { - "flag": "json-config-flag", - "variationType": "JSON", - "defaultValue": { - "foo": "bar" - }, - "targetingKey": "bob", - "attributes": { - "email": "bob@example.com", - "country": "Canada" - }, - "result": { - "value": { - "integer": 2, - "string": "two", - "float": 2.0 - }, - "variant": "two", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "object", - "doLog": true - } - } - }, - { - "flag": "json-config-flag", - "variationType": "JSON", - "defaultValue": { - "foo": "bar" - }, - "targetingKey": "charlie", - "attributes": { - "age": 50 - }, - "result": { - "value": { - "integer": 2, - "string": "two", - "float": 2.0 - }, - "variant": "two", - "flagMetadata": { - "allocationKey": "50/50 split", - "variationType": "object", - "doLog": true - } - } - }, - { - "flag": "json-config-flag", - "variationType": "JSON", - "defaultValue": { - "foo": "bar" - }, - "targetingKey": "diana", - "attributes": { - "Force Empty": true - }, - "result": { - "value": {}, - "variant": "empty", - "flagMetadata": { - "allocationKey": "Optionally Force Empty", - "variationType": "object", - "doLog": true - } - } - } -] diff --git a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-string-with-special-characters.json b/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-string-with-special-characters.json deleted file mode 100644 index 27d063122c00..000000000000 --- a/tracer/test/Datadog.Trace.Tests/FeatureFlags/resources/data/test-string-with-special-characters.json +++ /dev/null @@ -1,1190 +0,0 @@ -[ - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_spaces", - "attributes": { - "string_with_spaces": true - }, - "result": { - "value": " a b c d e f ", - "variant": "string_with_spaces", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_spaces", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_space", - "attributes": { - "string_with_only_one_space": true - }, - "result": { - "value": " ", - "variant": "string_with_only_one_space", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_space", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_spaces", - "attributes": { - "string_with_only_multiple_spaces": true - }, - "result": { - "value": " ", - "variant": "string_with_only_multiple_spaces", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_spaces", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_dots", - "attributes": { - "string_with_dots": true - }, - "result": { - "value": ".a.b.c.d.e.f.", - "variant": "string_with_dots", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_dots", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_dot", - "attributes": { - "string_with_only_one_dot": true - }, - "result": { - "value": ".", - "variant": "string_with_only_one_dot", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_dot", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_dots", - "attributes": { - "string_with_only_multiple_dots": true - }, - "result": { - "value": ".......", - "variant": "string_with_only_multiple_dots", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_dots", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_comas", - "attributes": { - "string_with_comas": true - }, - "result": { - "value": ",a,b,c,d,e,f,", - "variant": "string_with_comas", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_comas", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_coma", - "attributes": { - "string_with_only_one_coma": true - }, - "result": { - "value": ",", - "variant": "string_with_only_one_coma", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_coma", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_comas", - "attributes": { - "string_with_only_multiple_comas": true - }, - "result": { - "value": ",,,,,,,", - "variant": "string_with_only_multiple_comas", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_comas", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_colons", - "attributes": { - "string_with_colons": true - }, - "result": { - "value": ":a:b:c:d:e:f:", - "variant": "string_with_colons", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_colons", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_colon", - "attributes": { - "string_with_only_one_colon": true - }, - "result": { - "value": ":", - "variant": "string_with_only_one_colon", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_colon", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_colons", - "attributes": { - "string_with_only_multiple_colons": true - }, - "result": { - "value": ":::::::", - "variant": "string_with_only_multiple_colons", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_colons", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_semicolons", - "attributes": { - "string_with_semicolons": true - }, - "result": { - "value": ";a;b;c;d;e;f;", - "variant": "string_with_semicolons", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_semicolons", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_semicolon", - "attributes": { - "string_with_only_one_semicolon": true - }, - "result": { - "value": ";", - "variant": "string_with_only_one_semicolon", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_semicolon", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_semicolons", - "attributes": { - "string_with_only_multiple_semicolons": true - }, - "result": { - "value": ";;;;;;;", - "variant": "string_with_only_multiple_semicolons", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_semicolons", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_slashes", - "attributes": { - "string_with_slashes": true - }, - "result": { - "value": "/a/b/c/d/e/f/", - "variant": "string_with_slashes", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_slashes", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_slash", - "attributes": { - "string_with_only_one_slash": true - }, - "result": { - "value": "/", - "variant": "string_with_only_one_slash", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_slash", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_slashes", - "attributes": { - "string_with_only_multiple_slashes": true - }, - "result": { - "value": "///////", - "variant": "string_with_only_multiple_slashes", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_slashes", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_dashes", - "attributes": { - "string_with_dashes": true - }, - "result": { - "value": "-a-b-c-d-e-f-", - "variant": "string_with_dashes", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_dashes", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_dash", - "attributes": { - "string_with_only_one_dash": true - }, - "result": { - "value": "-", - "variant": "string_with_only_one_dash", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_dash", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_dashes", - "attributes": { - "string_with_only_multiple_dashes": true - }, - "result": { - "value": "-------", - "variant": "string_with_only_multiple_dashes", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_dashes", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_underscores", - "attributes": { - "string_with_underscores": true - }, - "result": { - "value": "_a_b_c_d_e_f_", - "variant": "string_with_underscores", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_underscores", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_underscore", - "attributes": { - "string_with_only_one_underscore": true - }, - "result": { - "value": "_", - "variant": "string_with_only_one_underscore", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_underscore", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_underscores", - "attributes": { - "string_with_only_multiple_underscores": true - }, - "result": { - "value": "_______", - "variant": "string_with_only_multiple_underscores", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_underscores", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_plus_signs", - "attributes": { - "string_with_plus_signs": true - }, - "result": { - "value": "+a+b+c+d+e+f+", - "variant": "string_with_plus_signs", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_plus_signs", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_plus_sign", - "attributes": { - "string_with_only_one_plus_sign": true - }, - "result": { - "value": "+", - "variant": "string_with_only_one_plus_sign", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_plus_sign", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_plus_signs", - "attributes": { - "string_with_only_multiple_plus_signs": true - }, - "result": { - "value": "+++++++", - "variant": "string_with_only_multiple_plus_signs", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_plus_signs", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_equal_signs", - "attributes": { - "string_with_equal_signs": true - }, - "result": { - "value": "=a=b=c=d=e=f=", - "variant": "string_with_equal_signs", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_equal_signs", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_equal_sign", - "attributes": { - "string_with_only_one_equal_sign": true - }, - "result": { - "value": "=", - "variant": "string_with_only_one_equal_sign", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_equal_sign", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_equal_signs", - "attributes": { - "string_with_only_multiple_equal_signs": true - }, - "result": { - "value": "=======", - "variant": "string_with_only_multiple_equal_signs", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_equal_signs", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_dollar_signs", - "attributes": { - "string_with_dollar_signs": true - }, - "result": { - "value": "$a$b$c$d$e$f$", - "variant": "string_with_dollar_signs", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_dollar_signs", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_dollar_sign", - "attributes": { - "string_with_only_one_dollar_sign": true - }, - "result": { - "value": "$", - "variant": "string_with_only_one_dollar_sign", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_dollar_sign", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_dollar_signs", - "attributes": { - "string_with_only_multiple_dollar_signs": true - }, - "result": { - "value": "$$$$$$$", - "variant": "string_with_only_multiple_dollar_signs", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_dollar_signs", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_at_signs", - "attributes": { - "string_with_at_signs": true - }, - "result": { - "value": "@a@b@c@d@e@f@", - "variant": "string_with_at_signs", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_at_signs", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_at_sign", - "attributes": { - "string_with_only_one_at_sign": true - }, - "result": { - "value": "@", - "variant": "string_with_only_one_at_sign", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_at_sign", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_at_signs", - "attributes": { - "string_with_only_multiple_at_signs": true - }, - "result": { - "value": "@@@@@@@", - "variant": "string_with_only_multiple_at_signs", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_at_signs", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_amp_signs", - "attributes": { - "string_with_amp_signs": true - }, - "result": { - "value": "&a&b&c&d&e&f&", - "variant": "string_with_amp_signs", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_amp_signs", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_amp_sign", - "attributes": { - "string_with_only_one_amp_sign": true - }, - "result": { - "value": "&", - "variant": "string_with_only_one_amp_sign", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_amp_sign", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_amp_signs", - "attributes": { - "string_with_only_multiple_amp_signs": true - }, - "result": { - "value": "&&&&&&&", - "variant": "string_with_only_multiple_amp_signs", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_amp_signs", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_hash_signs", - "attributes": { - "string_with_hash_signs": true - }, - "result": { - "value": "#a#b#c#d#e#f#", - "variant": "string_with_hash_signs", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_hash_signs", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_hash_sign", - "attributes": { - "string_with_only_one_hash_sign": true - }, - "result": { - "value": "#", - "variant": "string_with_only_one_hash_sign", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_hash_sign", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_hash_signs", - "attributes": { - "string_with_only_multiple_hash_signs": true - }, - "result": { - "value": "#######", - "variant": "string_with_only_multiple_hash_signs", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_hash_signs", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_percentage_signs", - "attributes": { - "string_with_percentage_signs": true - }, - "result": { - "value": "%a%b%c%d%e%f%", - "variant": "string_with_percentage_signs", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_percentage_signs", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_percentage_sign", - "attributes": { - "string_with_only_one_percentage_sign": true - }, - "result": { - "value": "%", - "variant": "string_with_only_one_percentage_sign", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_percentage_sign", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_percentage_signs", - "attributes": { - "string_with_only_multiple_percentage_signs": true - }, - "result": { - "value": "%%%%%%%", - "variant": "string_with_only_multiple_percentage_signs", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_percentage_signs", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_tilde_signs", - "attributes": { - "string_with_tilde_signs": true - }, - "result": { - "value": "~a~b~c~d~e~f~", - "variant": "string_with_tilde_signs", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_tilde_signs", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_tilde_sign", - "attributes": { - "string_with_only_one_tilde_sign": true - }, - "result": { - "value": "~", - "variant": "string_with_only_one_tilde_sign", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_tilde_sign", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_tilde_signs", - "attributes": { - "string_with_only_multiple_tilde_signs": true - }, - "result": { - "value": "~~~~~~~", - "variant": "string_with_only_multiple_tilde_signs", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_tilde_signs", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_asterix_signs", - "attributes": { - "string_with_asterix_signs": true - }, - "result": { - "value": "*a*b*c*d*e*f*", - "variant": "string_with_asterix_signs", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_asterix_signs", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_asterix_sign", - "attributes": { - "string_with_only_one_asterix_sign": true - }, - "result": { - "value": "*", - "variant": "string_with_only_one_asterix_sign", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_asterix_sign", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_asterix_signs", - "attributes": { - "string_with_only_multiple_asterix_signs": true - }, - "result": { - "value": "*******", - "variant": "string_with_only_multiple_asterix_signs", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_asterix_signs", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_single_quotes", - "attributes": { - "string_with_single_quotes": true - }, - "result": { - "value": "'a'b'c'd'e'f'", - "variant": "string_with_single_quotes", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_single_quotes", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_single_quote", - "attributes": { - "string_with_only_one_single_quote": true - }, - "result": { - "value": "'", - "variant": "string_with_only_one_single_quote", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_single_quote", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_single_quotes", - "attributes": { - "string_with_only_multiple_single_quotes": true - }, - "result": { - "value": "'''''''", - "variant": "string_with_only_multiple_single_quotes", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_single_quotes", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_question_marks", - "attributes": { - "string_with_question_marks": true - }, - "result": { - "value": "?a?b?c?d?e?f?", - "variant": "string_with_question_marks", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_question_marks", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_question_mark", - "attributes": { - "string_with_only_one_question_mark": true - }, - "result": { - "value": "?", - "variant": "string_with_only_one_question_mark", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_question_mark", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_question_marks", - "attributes": { - "string_with_only_multiple_question_marks": true - }, - "result": { - "value": "???????", - "variant": "string_with_only_multiple_question_marks", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_question_marks", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_exclamation_marks", - "attributes": { - "string_with_exclamation_marks": true - }, - "result": { - "value": "!a!b!c!d!e!f!", - "variant": "string_with_exclamation_marks", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_exclamation_marks", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_exclamation_mark", - "attributes": { - "string_with_only_one_exclamation_mark": true - }, - "result": { - "value": "!", - "variant": "string_with_only_one_exclamation_mark", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_exclamation_mark", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_exclamation_marks", - "attributes": { - "string_with_only_multiple_exclamation_marks": true - }, - "result": { - "value": "!!!!!!!", - "variant": "string_with_only_multiple_exclamation_marks", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_exclamation_marks", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_opening_parentheses", - "attributes": { - "string_with_opening_parentheses": true - }, - "result": { - "value": "(a(b(c(d(e(f(", - "variant": "string_with_opening_parentheses", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_opening_parentheses", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_opening_parenthese", - "attributes": { - "string_with_only_one_opening_parenthese": true - }, - "result": { - "value": "(", - "variant": "string_with_only_one_opening_parenthese", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_opening_parenthese", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_opening_parentheses", - "attributes": { - "string_with_only_multiple_opening_parentheses": true - }, - "result": { - "value": "(((((((", - "variant": "string_with_only_multiple_opening_parentheses", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_opening_parentheses", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_closing_parentheses", - "attributes": { - "string_with_closing_parentheses": true - }, - "result": { - "value": ")a)b)c)d)e)f)", - "variant": "string_with_closing_parentheses", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_closing_parentheses", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_one_closing_parenthese", - "attributes": { - "string_with_only_one_closing_parenthese": true - }, - "result": { - "value": ")", - "variant": "string_with_only_one_closing_parenthese", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_one_closing_parenthese", - "variationType": "string", - "doLog": true - } - } - }, - { - "flag": "string_flag_with_special_characters", - "variationType": "STRING", - "defaultValue": "default_value", - "targetingKey": "string_with_only_multiple_closing_parentheses", - "attributes": { - "string_with_only_multiple_closing_parentheses": true - }, - "result": { - "value": ")))))))", - "variant": "string_with_only_multiple_closing_parentheses", - "flagMetadata": { - "allocationKey": "allocation-test-string_with_only_multiple_closing_parentheses", - "variationType": "string", - "doLog": true - } - } - } -]