Skip to content

Commit

Permalink
FFM-11548 Add new jsonVariationToken method and deprecate `jsonVari…
Browse files Browse the repository at this point in the history
…ation` (#132)
  • Loading branch information
erdirowlands authored Jun 17, 2024
1 parent 0940c58 commit e1f539e
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 3 deletions.
5 changes: 5 additions & 0 deletions client/api/CfClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ public interface ICfClient
bool boolVariation(string key, dto.Target target, bool defaultValue);
string stringVariation(string key, dto.Target target, string defaultValue);
double numberVariation(string key, dto.Target target, double defaultValue);
JToken jsonVariationToken(string key, dto.Target target, JToken defaultValue);
JObject jsonVariation(string key, dto.Target target, JObject defaultValue);


event EventHandler InitializationCompleted;
event EventHandler<string> EvaluationChanged;

Expand Down Expand Up @@ -210,8 +212,11 @@ public async Task Initialize(IConnector connector, Config config)
public bool boolVariation(string key, dto.Target target, bool defaultValue) { return client.BoolVariation(key, target, defaultValue); }
public string stringVariation(string key, dto.Target target, string defaultValue) { return client.StringVariation(key, target, defaultValue); }
public double numberVariation(string key, dto.Target target, double defaultValue) { return client.NumberVariation(key, target, defaultValue); }
public JToken jsonVariationToken(string key, dto.Target target, JToken defaultValue) { return client.JsonVariationToken(key, target, defaultValue); }
[Obsolete("This method only supports JSON objects. If a JSON array variation is returned it will result in a warning being logged and the default variation being returned. Use jsonVariationToken(string key, Target target, JToken defaultValue) since version 1.7.0 for support of both JSON objects and arrays.")]
public JObject jsonVariation(string key, dto.Target target, JObject defaultValue) { return client.JsonVariation(key, target, defaultValue); }


// force message
public void Update(Message msg) { client.Update(msg, true); }

Expand Down
47 changes: 46 additions & 1 deletion client/api/Evaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Newtonsoft.Json.Linq;
using Target = io.harness.cfsdk.client.dto.Target;
using System.Collections.Generic;
using Newtonsoft.Json;

[assembly: InternalsVisibleToAttribute("ff-server-sdk-test")]

Expand All @@ -24,7 +25,9 @@ internal interface IEvaluator
bool BoolVariation(string key, Target target, bool defaultValue);
string StringVariation(string key, Target target, string defaultValue);
double NumberVariation(string key, Target target, double defaultValue);
JToken JsonVariationToken(string key, Target target, JToken defaultValue);
JObject JsonVariation(string key, Target target, JObject defaultValue);

}

internal class Evaluator : IEvaluator
Expand Down Expand Up @@ -60,10 +63,52 @@ public bool BoolVariation(string key, Target target, bool defaultValue)
return defaultValue;
}

public JToken JsonVariationToken(string key, Target target, JToken defaultValue)
{
var variation = EvaluateVariation(key, target, FeatureConfigKind.Json);
if (variation == null)
{
LogEvaluationFailureError(FeatureConfigKind.Json, key, target, defaultValue.ToString());
return defaultValue;
}

try
{
return JToken.Parse(variation.Value);
}
catch (JsonReaderException ex)
{
if (!logger.IsEnabled(LogLevel.Warning)) return defaultValue;

LogEvaluationFailureError(FeatureConfigKind.Json, key, target, defaultValue.ToString());
return defaultValue;
}

}

public JObject JsonVariation(string key, Target target, JObject defaultValue)
{
var variation = EvaluateVariation(key, target, FeatureConfigKind.Json);
if (variation != null) return JObject.Parse(variation.Value);
if (variation != null)
{
try
{
var token = JToken.Parse(variation.Value);
if (token.Type == JTokenType.Object) return (JObject)token;

if (!logger.IsEnabled(LogLevel.Warning)) return defaultValue;

logger.LogWarning("JSON variation is not an object. Returning default value. Use JsonVariationToken(string key, Target target, JToken defaultValue) which is available since version 1.7.0");
LogEvaluationFailureError(FeatureConfigKind.Json, key, target, defaultValue.ToString());
return defaultValue;
}
catch (JsonReaderException ex)
{
// Log the error if parsing fails
LogEvaluationFailureError(FeatureConfigKind.Json, key, target, ex.Message);
return defaultValue;
}
}

LogEvaluationFailureError(FeatureConfigKind.Json, key, target, defaultValue.ToString());
return defaultValue;
Expand Down
40 changes: 40 additions & 0 deletions client/api/InnerClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,45 @@ public double NumberVariation(string key, Target target, double defaultValue)
}
}

public JToken JsonVariationToken(string key, Target target, JToken defaultValue)
{
try
{
return evaluator.JsonVariationToken(key, target, defaultValue);
}
catch (InvalidCacheStateException ex)
{
if (logger.IsEnabled(LogLevel.Warning))
logger.LogWarning(ex,
"Invalid cache state detected when evaluating json variation for flag {Key}, refreshing cache and retrying evaluation",
key);
var result = polling.RefreshFlagsAndSegments(TimeSpan.FromSeconds(config.CacheRecoveryTimeoutInMs));
if (result != RefreshOutcome.Success)
{
if (logger.IsEnabled(LogLevel.Error))
logger.LogError(
"Refreshing cache for json variation for flag {Key} failed, returning default variation",
key);
LogEvaluationFailureError(FeatureConfigKind.Json, key, target, defaultValue.ToString());
return defaultValue;
}

try
{
return evaluator.JsonVariationToken(key, target, defaultValue);
}
catch (InvalidCacheStateException)
{
if (logger.IsEnabled(LogLevel.Warning))
logger.LogWarning(
"Attempted re-evaluation of json variation for flag {Key} after refreshing cache failed due to invalid cache state, returning default variation",
key);
LogEvaluationFailureError(FeatureConfigKind.Json, key, target, defaultValue.ToString());
return defaultValue;
}
}
}


public JObject JsonVariation(string key, Target target, JObject defaultValue)
{
Expand Down Expand Up @@ -378,6 +417,7 @@ public JObject JsonVariation(string key, Target target, JObject defaultValue)
}



public void Close()
{
this.connector?.Close();
Expand Down
4 changes: 2 additions & 2 deletions ff-netF48-server-sdk.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
<PackageId>ff-dotnet-server-sdk</PackageId>
<RootNamespace>io.harness.cfsdk</RootNamespace>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>1.7.0-rc3</Version>
<Version>1.7.0</Version>
<PackOnBuild>true</PackOnBuild>
<PackageVersion>1.7.0-rc3</PackageVersion>
<PackageVersion>1.7.0</PackageVersion>
<AssemblyVersion>1.7.0</AssemblyVersion>
<Authors>[email protected]</Authors>
<Copyright>Copyright © 2024</Copyright>
Expand Down
3 changes: 3 additions & 0 deletions tests/ff-server-sdk-test/EvaluatorTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ public void ExecuteTestCases(string testName, string targetIdentifier, object ex
}

object got = null;
object gotJsonTokenMethod = null;

switch (kind)
{
Expand All @@ -175,6 +176,7 @@ public void ExecuteTestCases(string testName, string targetIdentifier, object ex
break;
case FeatureConfigKind.Json:
got = evaluator.JsonVariation(featureFlag, target, JObject.Parse("{val: 'default value'}"));
gotJsonTokenMethod = evaluator.JsonVariationToken(featureFlag, target, JObject.Parse("{val: 'default value'}"));
break;
}

Expand All @@ -188,6 +190,7 @@ public void ExecuteTestCases(string testName, string targetIdentifier, object ex
{
var expectedJson = JObject.Parse((string)expected);
Assert.AreEqual(expectedJson, got, $"Expected result for {featureFlag} was {expected}");
Assert.AreEqual(expectedJson, gotJsonTokenMethod, $"Expected result for {featureFlag} was {expected}");
}
else
{
Expand Down

0 comments on commit e1f539e

Please sign in to comment.