From 0404614cd8b54977ad4c9fa308cced42c8d97868 Mon Sep 17 00:00:00 2001 From: Vladimir Petrusevici Date: Wed, 18 Oct 2023 15:59:09 +0300 Subject: [PATCH] add tests. handle parse error --- .../FlagsmithProvider.cs | 25 +- .../FlagsmithProviderTest.cs | 368 +++++++++++++++++- 2 files changed, 381 insertions(+), 12 deletions(-) diff --git a/src/OpenFeature.Contrib.Providers.Flagsmith/FlagsmithProvider.cs b/src/OpenFeature.Contrib.Providers.Flagsmith/FlagsmithProvider.cs index 6148eacb..38e40ebc 100644 --- a/src/OpenFeature.Contrib.Providers.Flagsmith/FlagsmithProvider.cs +++ b/src/OpenFeature.Contrib.Providers.Flagsmith/FlagsmithProvider.cs @@ -1,6 +1,4 @@ using Flagsmith; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using OpenFeature.Constant; using OpenFeature.Model; using System.Collections.Generic; @@ -49,9 +47,9 @@ public FlagsmithProvider(IFlagsmithClient flagsmithClient) _flagsmithClient = flagsmithClient; } - private Task GetFlags(EvaluationContext ctx) + private Task GetFlags(EvaluationContext ctx = null) { - var key = ctx.GetValue("targetingKey").AsString; + var key = ctx?.GetValue("targetingKey")?.AsString; return string.IsNullOrEmpty(key) ? _flagsmithClient.GetEnvironmentFlags() : _flagsmithClient.GetIdentityFlags(key, ctx.AsDictionary().Select(x => new Trait(x.Key, x.Value.AsObject) as ITrait).ToList()); @@ -148,13 +146,22 @@ public override async Task> ResolveStructureValue(strin } var stringValue = await flags.GetFeatureValue(flagKey); - var mappedValue = JsonNode.Parse(stringValue); - var value = ConvertValue(mappedValue); - if (value is null) + try { - return new ResolutionDetails(flagKey, defaultValue, ErrorType.ParseError, Reason.Error, errorMessage: "Failed to parse value in structure type or value is null"); + var mappedValue = JsonNode.Parse(stringValue); + var value = ConvertValue(mappedValue); + if (value is not null) + { + return new ResolutionDetails(flagKey, value); + + } } - return new ResolutionDetails(flagKey, value); + catch + { + + } + return new ResolutionDetails(flagKey, defaultValue, ErrorType.ParseError, Reason.Error, errorMessage: "Failed to parse value in structure type or value is null"); + } /// diff --git a/test/OpenFeature.Contrib.Providers.Flagsmith.Test/FlagsmithProviderTest.cs b/test/OpenFeature.Contrib.Providers.Flagsmith.Test/FlagsmithProviderTest.cs index 042412e0..9c35866e 100644 --- a/test/OpenFeature.Contrib.Providers.Flagsmith.Test/FlagsmithProviderTest.cs +++ b/test/OpenFeature.Contrib.Providers.Flagsmith.Test/FlagsmithProviderTest.cs @@ -2,6 +2,11 @@ using System; using Flagsmith; using System.Net.Http; +using NSubstitute; +using System.Threading.Tasks; +using OpenFeature.Constant; +using OpenFeature.Model; +using System.Linq; namespace OpenFeature.Contrib.Providers.Flagsmith.Test { @@ -45,16 +50,373 @@ public void CreateFlagmithProvider_WithValidCredetialsAndCustomHttpClient_Create } [Fact] - public void CreateFlagmithProvider_WithCustomFlagsmithClient_CreatesInstanceSuccessfully() + public async Task GetBooleanValue_ForEnabledFeatureWithValidFormat_ReturnCorrectValue() { // Arrange - var flagsmithClient = new FlagsmithClient(GetDefaultFlagsmithConfiguration()); + var flagsmithClient = Substitute.For(); + var flags = Substitute.For(); + flags.GetFeatureValue("example-feature").Returns("true"); + flags.IsFeatureEnabled("example-feature").Returns(true); + flagsmithClient.GetEnvironmentFlags().Returns(flags); + + var flagsmithProvider = new FlagsmithProvider(flagsmithClient); + // Act + var result = await flagsmithProvider.ResolveBooleanValue("example-feature", false); + + // Assert + Assert.True(result.Value); + Assert.Equal("example-feature", result.FlagKey); + Assert.Null(result.Reason); + Assert.Equal(ErrorType.None, result.ErrorType); + } + + [Fact] + public async Task GetBooleanValue_ForDisabledFeatureWithValidFormat_ReturnDefaultValue() + { + // Arrange + var flagsmithClient = Substitute.For(); + var flags = Substitute.For(); + flags.GetFeatureValue("example-feature").Returns("false"); + flags.IsFeatureEnabled("example-feature").Returns(false); + flagsmithClient.GetEnvironmentFlags().Returns(flags); + var flagsmithProvider = new FlagsmithProvider(flagsmithClient); + // Act + var result = await flagsmithProvider.ResolveBooleanValue("example-feature", true); // Assert - Assert.NotNull(flagsmithProvider._flagsmithClient); + Assert.True(result.Value); + Assert.Equal("example-feature", result.FlagKey); + Assert.Equal(Reason.Disabled, result.Reason); + Assert.Equal(ErrorType.None, result.ErrorType); + } + + [Fact] + public async Task GetBooleanValue_ForEnabledFeatureWithWrongFormatValue_ReturnDefaultValue() + { + // Arrange + var flagsmithClient = Substitute.For(); + var flags = Substitute.For(); + flags.GetFeatureValue("example-feature").Returns("hreni"); + flags.IsFeatureEnabled("example-feature").Returns(true); + flagsmithClient.GetEnvironmentFlags().Returns(flags); + + var flagsmithProvider = new FlagsmithProvider(flagsmithClient); + + // Act + var result = await flagsmithProvider.ResolveBooleanValue("example-feature", true); + + // Assert + Assert.True(result.Value); + Assert.Equal("example-feature", result.FlagKey); + Assert.Equal(Reason.Error, result.Reason); + Assert.Equal(ErrorType.ParseError, result.ErrorType); + } + + + [Fact] + public async Task GetDoubleValue_ForEnabledFeatureWithValidFormat_ReturnCorrectValue() + { + // Arrange + var flagsmithClient = Substitute.For(); + var flags = Substitute.For(); + flags.GetFeatureValue("example-feature").Returns("32.334"); + flags.IsFeatureEnabled("example-feature").Returns(true); + flagsmithClient.GetEnvironmentFlags().Returns(flags); + + var flagsmithProvider = new FlagsmithProvider(flagsmithClient); + + // Act + var result = await flagsmithProvider.ResolveDoubleValue("example-feature", 32.334); + + // Assert + Assert.Equal(32.334, result.Value); + Assert.Equal("example-feature", result.FlagKey); + Assert.Null(result.Reason); + Assert.Equal(ErrorType.None, result.ErrorType); + } + + + [Fact] + public async Task GetDoubleValue_ForDisabledFeatureWithValidFormat_ReturnDefaultValue() + { + // Arrange + var flagsmithClient = Substitute.For(); + var flags = Substitute.For(); + flags.GetFeatureValue("example-feature").Returns("4112"); + flags.IsFeatureEnabled("example-feature").Returns(false); + flagsmithClient.GetEnvironmentFlags().Returns(flags); + + var flagsmithProvider = new FlagsmithProvider(flagsmithClient); + + // Act + var result = await flagsmithProvider.ResolveDoubleValue("example-feature", -32.22); + + // Assert + Assert.Equal(-32.22, result.Value); + Assert.Equal("example-feature", result.FlagKey); + Assert.Equal(Reason.Disabled, result.Reason); + Assert.Equal(ErrorType.None, result.ErrorType); + } + + [Fact] + public async Task GetDoubleValue_ForEnabledFeatureWithWrongFormatValue_ReturnDefaultValue() + { + // Arrange + var flagsmithClient = Substitute.For(); + var flags = Substitute.For(); + flags.GetFeatureValue("example-feature").Returns("hreni"); + flags.IsFeatureEnabled("example-feature").Returns(true); + flagsmithClient.GetEnvironmentFlags().Returns(flags); + + var flagsmithProvider = new FlagsmithProvider(flagsmithClient); + + // Act + var result = await flagsmithProvider.ResolveDoubleValue("example-feature", 2222.22133); + + // Assert + Assert.Equal(2222.22133, result.Value); + Assert.Equal("example-feature", result.FlagKey); + Assert.Equal(Reason.Error, result.Reason); + Assert.Equal(ErrorType.ParseError, result.ErrorType); + } + + + + [Fact] + public async Task GetStringValue_ForEnabledFeatureWithValidFormat_ReturnCorrectValue() + { + // Arrange + var flagsmithClient = Substitute.For(); + var flags = Substitute.For(); + flags.GetFeatureValue("example-feature").Returns("example"); + flags.IsFeatureEnabled("example-feature").Returns(true); + flagsmithClient.GetEnvironmentFlags().Returns(flags); + + var flagsmithProvider = new FlagsmithProvider(flagsmithClient); + + // Act + var result = await flagsmithProvider.ResolveStringValue("example-feature", "example"); + + // Assert + Assert.Equal("example", result.Value); + Assert.Equal("example-feature", result.FlagKey); + Assert.Null(result.Reason); + Assert.Equal(ErrorType.None, result.ErrorType); + } + + + [Fact] + public async Task GetStringValue_ForDisabledFeatureWithValidFormat_ReturnDefaultValue() + { + // Arrange + var flagsmithClient = Substitute.For(); + var flags = Substitute.For(); + flags.GetFeatureValue("example-feature").Returns("4112"); + flags.IsFeatureEnabled("example-feature").Returns(false); + flagsmithClient.GetEnvironmentFlags().Returns(flags); + + var flagsmithProvider = new FlagsmithProvider(flagsmithClient); + + // Act + var result = await flagsmithProvider.ResolveStringValue("example-feature", "3333a"); + + // Assert + Assert.Equal("3333a", result.Value); + Assert.Equal("example-feature", result.FlagKey); + Assert.Equal(Reason.Disabled, result.Reason); + Assert.Equal(ErrorType.None, result.ErrorType); + } + + + [Fact] + public async Task GetIntValue_ForEnabledFeatureWithValidFormat_ReturnCorrectValue() + { + // Arrange + var flagsmithClient = Substitute.For(); + var flags = Substitute.For(); + flags.GetFeatureValue("example-feature").Returns("232"); + flags.IsFeatureEnabled("example-feature").Returns(true); + flagsmithClient.GetEnvironmentFlags().Returns(flags); + + var flagsmithProvider = new FlagsmithProvider(flagsmithClient); + + // Act + var result = await flagsmithProvider.ResolveIntegerValue("example-feature", 32); + + // Assert + Assert.Equal(232, result.Value); + Assert.Equal("example-feature", result.FlagKey); + Assert.Null(result.Reason); + Assert.Equal(ErrorType.None, result.ErrorType); + } + + [Fact] + public async Task GetIntValue_ForDisabledFeatureWithValidFormat_ReturnDefaultValue() + { + // Arrange + var flagsmithClient = Substitute.For(); + var flags = Substitute.For(); + flags.GetFeatureValue("example-feature").Returns("4112"); + flags.IsFeatureEnabled("example-feature").Returns(false); + flagsmithClient.GetEnvironmentFlags().Returns(flags); + + var flagsmithProvider = new FlagsmithProvider(flagsmithClient); + + // Act + var result = await flagsmithProvider.ResolveIntegerValue("example-feature", -32); + + // Assert + Assert.Equal(-32, result.Value); + Assert.Equal("example-feature", result.FlagKey); + Assert.Equal(Reason.Disabled, result.Reason); + Assert.Equal(ErrorType.None, result.ErrorType); + } + + [Fact] + public async Task GetIntValue_ForEnabledFeatureWithWrongFormatValue_ReturnDefaultValue() + { + // Arrange + var flagsmithClient = Substitute.For(); + var flags = Substitute.For(); + flags.GetFeatureValue("example-feature").Returns("hreni"); + flags.IsFeatureEnabled("example-feature").Returns(true); + flagsmithClient.GetEnvironmentFlags().Returns(flags); + + var flagsmithProvider = new FlagsmithProvider(flagsmithClient); + + // Act + var result = await flagsmithProvider.ResolveIntegerValue("example-feature", 2222); + + // Assert + Assert.Equal(2222, result.Value); + Assert.Equal("example-feature", result.FlagKey); + Assert.Equal(Reason.Error, result.Reason); + Assert.Equal(ErrorType.ParseError, result.ErrorType); + } + + [Fact] + public async Task GetStructureValue_ForEnabledFeatureWithValidFormat_ReturnCorrectValue() + { + // Arrange + var flagsmithClient = Substitute.For(); + var flags = Substitute.For(); + var expectedValue = + """ + { + "glossary": { + "title": "example glossary", + "GlossDiv": { + "title": "S", + "GlossList": { + "GlossEntry": { + "ID": "SGML", + "SortAs": "SGML", + "GlossTerm": "Standard Generalized Markup Language", + "Acronym": "SGML", + "Abbrev": "ISO 8879:1986", + "GlossDef": { + "para": "A meta-markup language, used to create markup languages such as DocBook.", + "GlossSeeAlso": [ + "GML", + "XML" + ] + }, + "GlossSee": "markup" + } + } + } + } + } + """; + flags.GetFeatureValue("example-feature").Returns(expectedValue); + flags.IsFeatureEnabled("example-feature").Returns(true); + flagsmithClient.GetEnvironmentFlags().Returns(flags); + + var flagsmithProvider = new FlagsmithProvider(flagsmithClient); + + // Act + var defaultObject = new Value(Structure.Empty); + + var result = await flagsmithProvider.ResolveStructureValue("example-feature", defaultObject); + + // Assert + var glossary = result.Value.AsStructure.GetValue("glossary"); + Assert.True(glossary.IsStructure); + Assert.Equal("example glossary", glossary.AsStructure.GetValue("title").AsString); + var glossDiv = glossary.AsStructure.GetValue("GlossDiv"); + Assert.True(glossDiv.IsStructure); + var glossList = glossDiv.AsStructure.GetValue("GlossList"); + Assert.True(glossList.IsStructure); + var glossEntry = glossList.AsStructure.GetValue("GlossEntry"); + Assert.True(glossEntry.IsStructure); + Assert.Equal("SGML", glossEntry.AsStructure.GetValue("SortAs").AsString); + var glossDef = glossEntry.AsStructure.GetValue("GlossDef"); + Assert.True(glossDef.IsStructure); + var glossSeeAlso = glossDef.AsStructure.GetValue("GlossSeeAlso"); + Assert.True(glossSeeAlso.IsList); + Assert.Equal(2, glossSeeAlso.AsList.Count); + Assert.Equal("GML", glossSeeAlso.AsList.First().AsString); + Assert.Equal("XML", glossSeeAlso.AsList.Last().AsString); + + Assert.Equal("example-feature", result.FlagKey); + Assert.Null(result.Reason); + Assert.Equal(ErrorType.None, result.ErrorType); + } + + [Fact] + public async Task GetStructureValue_ForDisabledFeatureWithValidFormat_ReturnDefaultValue() + { + // Arrange + var flagsmithClient = Substitute.For(); + var flags = Substitute.For(); + flags.GetFeatureValue("example-feature").Returns("4112"); + flags.IsFeatureEnabled("example-feature").Returns(false); + flagsmithClient.GetEnvironmentFlags().Returns(flags); + + var defaultObject = new Value("default"); + var flagsmithProvider = new FlagsmithProvider(flagsmithClient); + + // Act + var result = await flagsmithProvider.ResolveStructureValue("example-feature", defaultObject); + + // Assert + Assert.Equal(defaultObject, result.Value); + Assert.Equal("example-feature", result.FlagKey); + Assert.Equal(Reason.Disabled, result.Reason); + Assert.Equal(ErrorType.None, result.ErrorType); + } + + [Fact] + public async Task GetStructureValue_ForEnabledFeatureWithWrongFormatValue_ReturnDefaultValue() + { + // Arrange + var flagsmithClient = Substitute.For(); + var flags = Substitute.For(); + flags.GetFeatureValue("example-feature").Returns("hreni"); + flags.IsFeatureEnabled("example-feature").Returns(true); + flagsmithClient.GetEnvironmentFlags().Returns(flags); + + var defaultObject = new Value("default"); + var flagsmithProvider = new FlagsmithProvider(flagsmithClient); + + // Act + var result = await flagsmithProvider.ResolveStructureValue("example-feature", defaultObject); + + // Assert + Assert.Equal(defaultObject, result.Value); + Assert.Equal("example-feature", result.FlagKey); + Assert.Equal(Reason.Error, result.Reason); + Assert.Equal(ErrorType.ParseError, result.ErrorType); } } + + public class ExampleConfig + { + public string ExampleText { get; set; } + public int ExampleInt { get; set; } + } + }