Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Evaluation log improvements #89

Merged
merged 9 commits into from
Mar 21, 2024
8 changes: 4 additions & 4 deletions src/ConfigCat.Client.Tests/ConfigV2EvaluationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -736,10 +736,10 @@ public void ComparisonAttributeTrimming_Test(string key, string expectedReturnVa
[DataRow("notendswithanyof", "no trim")]
[DataRow("arraycontainsanyof", "no trim")]
[DataRow("arraynotcontainsanyof", "no trim")]
[DataRow("startwithanyofhashed", "default")]
[DataRow("notstartwithanyofhashed", "default")]
[DataRow("endswithanyofhashed", "default")]
[DataRow("notendswithanyofhashed", "default")]
[DataRow("startwithanyofhashed", "no trim")]
[DataRow("notstartwithanyofhashed", "no trim")]
[DataRow("endswithanyofhashed", "no trim")]
[DataRow("notendswithanyofhashed", "no trim")]
//semver comparator values trimmed because of backward compatibility
[DataRow("semverisoneof", "4 trim")]
[DataRow("semverisnotoneof", "5 trim")]
Expand Down
24 changes: 15 additions & 9 deletions src/ConfigCat.Client.Tests/UserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ public void CreateUser_WithIdAndEmailAndCountry_AllAttributesShouldContainsPasse
var user = new User("id")
{
Email = "[email protected]",

Country = "US"
};

Expand All @@ -25,12 +24,17 @@ public void CreateUser_WithIdAndEmailAndCountry_AllAttributesShouldContainsPasse

Assert.IsTrue(actualAttributes.TryGetValue(nameof(User.Email), out var s));
Assert.AreEqual("[email protected]", s);
Assert.AreEqual("[email protected]", user.GetAttribute(nameof(User.Email)));

Assert.IsTrue(actualAttributes.TryGetValue(nameof(User.Country), out s));
Assert.AreEqual("US", s);
Assert.AreEqual("US", user.GetAttribute(nameof(User.Country)));

Assert.IsTrue(actualAttributes.TryGetValue(nameof(User.Identifier), out s));
Assert.AreEqual("id", s);
Assert.AreEqual("id", user.GetAttribute(nameof(User.Identifier)));

Assert.AreEqual(3, actualAttributes.Count);
}

[TestMethod]
Expand All @@ -41,9 +45,7 @@ public void UseWellKnownAttributesAsCustomProperties_ShouldNotAppendAllAttribute
var user = new User("id")
{
Email = "[email protected]",

Country = "US",

Custom =
{
{ "myCustomAttribute", "myCustomAttributeValue"},
Expand All @@ -59,13 +61,17 @@ public void UseWellKnownAttributesAsCustomProperties_ShouldNotAppendAllAttribute

// Assert

Assert.IsTrue(actualAttributes.TryGetValue(nameof(User.Identifier), out var s));
Assert.AreEqual("id", s);
Assert.AreNotEqual("myIdentifier", s);
Assert.IsTrue(actualAttributes.TryGetValue(nameof(User.Email), out var s));
Assert.AreEqual("id@example.com", s);
Assert.AreEqual("[email protected]", user.GetAttribute(nameof(User.Email)));

Assert.IsTrue(actualAttributes.TryGetValue(nameof(User.Country), out s));
Assert.AreEqual("US", s);
Assert.AreNotEqual("United States", s);
Assert.AreEqual("US", user.GetAttribute(nameof(User.Country)));

Assert.IsTrue(actualAttributes.TryGetValue(nameof(User.Identifier), out s));
Assert.AreEqual("id", s);
Assert.AreEqual("id", user.GetAttribute(nameof(User.Identifier)));

Assert.IsTrue(actualAttributes.TryGetValue(nameof(User.Email), out s));
Assert.AreEqual("[email protected]", s);
Expand All @@ -89,9 +95,7 @@ public void UseWellKnownAttributesAsCustomPropertiesWithDifferentNames_ShouldApp
var user = new User("id")
{
Email = "[email protected]",

Country = "US",

Custom =
{
{ attributeName, attributeValue}
Expand All @@ -108,6 +112,7 @@ public void UseWellKnownAttributesAsCustomPropertiesWithDifferentNames_ShouldApp

Assert.IsTrue(actualAttributes.TryGetValue(attributeName, out var s));
Assert.AreEqual(attributeValue, s);
Assert.AreEqual(attributeValue, user.GetAttribute(attributeName));
}

[DataTestMethod()]
Expand All @@ -122,5 +127,6 @@ public void CreateUser_ShouldSetIdentifier(string identifier, string expectedVal

Assert.AreEqual(expectedValue, user.Identifier);
Assert.AreEqual(expectedValue, user.GetAllAttributes()[nameof(User.Identifier)]);
Assert.AreEqual(expectedValue, user.GetAttribute(nameof(User.Identifier)));
}
}
43 changes: 26 additions & 17 deletions src/ConfigCatClient/Evaluation/EvaluateLogHelper.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Globalization;
using ConfigCat.Client.Utils;

Expand All @@ -13,11 +14,6 @@ internal static class EvaluateLogHelper

internal const int StringListMaxLength = 10;

public static IndentedTextBuilder AppendEvaluationResult(this IndentedTextBuilder builder, bool result)
{
return builder.Append(result ? "true" : "false");
}

private static IndentedTextBuilder AppendUserCondition(this IndentedTextBuilder builder, string? comparisonAttribute, UserComparator comparator, object? comparisonValue)
{
return builder.Append($"User.{comparisonAttribute} {comparator.ToDisplayText()} '{comparisonValue ?? InvalidValuePlaceholder}'");
Expand Down Expand Up @@ -64,6 +60,8 @@ private static IndentedTextBuilder AppendUserCondition(this IndentedTextBuilder

public static IndentedTextBuilder AppendUserCondition(this IndentedTextBuilder builder, UserCondition condition)
{
var comparisonAttribute = condition.ComparisonAttribute ?? InvalidNamePlaceholder;

return condition.Comparator switch
{
UserComparator.IsOneOf or
Expand All @@ -78,23 +76,23 @@ UserComparator.TextEndsWithAnyOf or
UserComparator.TextNotEndsWithAnyOf or
UserComparator.ArrayContainsAnyOf or
UserComparator.ArrayNotContainsAnyOf =>
builder.AppendUserCondition(condition.ComparisonAttribute, condition.Comparator, condition.StringListValue, isSensitive: false),
builder.AppendUserCondition(comparisonAttribute, condition.Comparator, condition.StringListValue, isSensitive: false),

UserComparator.SemVerLess or
UserComparator.SemVerLessOrEquals or
UserComparator.SemVerGreater or
UserComparator.SemVerGreaterOrEquals or
UserComparator.TextEquals or
UserComparator.TextNotEquals =>
builder.AppendUserCondition(condition.ComparisonAttribute, condition.Comparator, condition.StringValue, isSensitive: false),
builder.AppendUserCondition(comparisonAttribute, condition.Comparator, condition.StringValue, isSensitive: false),

UserComparator.NumberEquals or
UserComparator.NumberNotEquals or
UserComparator.NumberLess or
UserComparator.NumberLessOrEquals or
UserComparator.NumberGreater or
UserComparator.NumberGreaterOrEquals =>
builder.AppendUserCondition(condition.ComparisonAttribute, condition.Comparator, condition.DoubleValue),
builder.AppendUserCondition(comparisonAttribute, condition.Comparator, condition.DoubleValue),

UserComparator.SensitiveIsOneOf or
UserComparator.SensitiveIsNotOneOf or
Expand All @@ -104,24 +102,28 @@ UserComparator.SensitiveTextEndsWithAnyOf or
UserComparator.SensitiveTextNotEndsWithAnyOf or
UserComparator.SensitiveArrayContainsAnyOf or
UserComparator.SensitiveArrayNotContainsAnyOf =>
builder.AppendUserCondition(condition.ComparisonAttribute, condition.Comparator, condition.StringListValue, isSensitive: true),
builder.AppendUserCondition(comparisonAttribute, condition.Comparator, condition.StringListValue, isSensitive: true),

UserComparator.DateTimeBefore or
UserComparator.DateTimeAfter =>
builder.AppendUserCondition(condition.ComparisonAttribute, condition.Comparator, condition.DoubleValue, isDateTime: true),
builder.AppendUserCondition(comparisonAttribute, condition.Comparator, condition.DoubleValue, isDateTime: true),

UserComparator.SensitiveTextEquals or
UserComparator.SensitiveTextNotEquals =>
builder.AppendUserCondition(condition.ComparisonAttribute, condition.Comparator, condition.StringValue, isSensitive: true),
builder.AppendUserCondition(comparisonAttribute, condition.Comparator, condition.StringValue, isSensitive: true),

_ =>
builder.AppendUserCondition(condition.ComparisonAttribute, condition.Comparator, condition.GetComparisonValue(throwIfInvalid: false)),
builder.AppendUserCondition(comparisonAttribute, condition.Comparator, condition.GetComparisonValue(throwIfInvalid: false)),
};
}

public static IndentedTextBuilder AppendPrerequisiteFlagCondition(this IndentedTextBuilder builder, PrerequisiteFlagCondition condition)
public static IndentedTextBuilder AppendPrerequisiteFlagCondition(this IndentedTextBuilder builder, PrerequisiteFlagCondition condition, IReadOnlyDictionary<string, Setting>? settings = null)
{
var prerequisiteFlagKey = condition.PrerequisiteFlagKey ?? InvalidReferencePlaceholder;
var prerequisiteFlagKey =
condition.PrerequisiteFlagKey is null ? InvalidNamePlaceholder :
settings is not null && !settings.ContainsKey(condition.PrerequisiteFlagKey) ? InvalidReferencePlaceholder :
condition.PrerequisiteFlagKey;

var comparator = condition.Comparator;
var comparisonValue = condition.ComparisonValue.GetValue(throwIfInvalid: false);

Expand All @@ -133,15 +135,22 @@ public static IndentedTextBuilder AppendSegmentCondition(this IndentedTextBuilde
var segment = condition.Segment;
var comparator = condition.Comparator;

var segmentName = segment?.Name ??
(segment is null ? InvalidReferencePlaceholder : InvalidNamePlaceholder);
var segmentName =
segment is null ? InvalidReferencePlaceholder :
segment.Name is not { Length: > 0 } ? InvalidNamePlaceholder :
segment.Name;

return builder.Append($"User {comparator.ToDisplayText()} '{segmentName}'");
}

public static IndentedTextBuilder AppendConditionResult(this IndentedTextBuilder builder, bool result)
{
return builder.Append(result ? "true" : "false");
}

public static IndentedTextBuilder AppendConditionConsequence(this IndentedTextBuilder builder, bool result)
{
builder.Append(" => ").AppendEvaluationResult(result);
builder.Append(" => ").AppendConditionResult(result);
return result ? builder : builder.Append(", skipping the remaining AND conditions");
}

Expand Down
19 changes: 12 additions & 7 deletions src/ConfigCatClient/Evaluation/RolloutEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ private static bool EvaluateSensitiveTextSliceEqualsAnyOf(string text, string[]?

var index = item.IndexOf('_');
if (index < 0
|| !int.TryParse(item.AsSpan(0, index).ToParsable(), NumberStyles.None, CultureInfo.InvariantCulture, out var sliceLength)
|| !int.TryParse(item.AsSpan(0, index).ToParsable(), NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite, CultureInfo.InvariantCulture, out var sliceLength)
|| (hash2 = item.AsSpan(index + 1)).IsEmpty)
{
EnsureComparisonValue<string>(null);
Expand Down Expand Up @@ -711,12 +711,17 @@ private static bool EvaluateSensitiveArrayContainsAnyOf(string[] array, string[]
private bool EvaluatePrerequisiteFlagCondition(PrerequisiteFlagCondition condition, ref EvaluateContext context)
{
var logBuilder = context.LogBuilder;
logBuilder?.AppendPrerequisiteFlagCondition(condition);
logBuilder?.AppendPrerequisiteFlagCondition(condition, context.Settings);

Setting? prerequisiteFlag;
var prerequisiteFlagKey = condition.PrerequisiteFlagKey;
if (prerequisiteFlagKey is null || !context.Settings.TryGetValue(prerequisiteFlagKey, out var prerequisiteFlag))
if (prerequisiteFlagKey is null)
{
throw new InvalidOperationException("Prerequisite flag key is missing or invalid.");
throw new InvalidOperationException("Prerequisite flag key is missing.");
}
else if (!context.Settings.TryGetValue(prerequisiteFlagKey, out prerequisiteFlag))
{
throw new InvalidOperationException("Prerequisite flag is missing.");
}

var comparisonValue = EnsureComparisonValue(condition.ComparisonValue.GetValue(throwIfInvalid: false));
Expand Down Expand Up @@ -759,8 +764,8 @@ private bool EvaluatePrerequisiteFlagCondition(PrerequisiteFlagCondition conditi
logBuilder?
.NewLine().Append($"Prerequisite flag evaluation result: '{prerequisiteFlagValue}'.")
.NewLine("Condition (")
.AppendPrerequisiteFlagCondition(condition)
.Append(") evaluates to ").AppendEvaluationResult(result).Append(".")
.AppendPrerequisiteFlagCondition(condition, context.Settings)
.Append(") evaluates to ").AppendConditionResult(result).Append(".")
.DecreaseIndent()
.NewLine(")");

Expand Down Expand Up @@ -818,7 +823,7 @@ private bool EvaluateSegmentCondition(SegmentCondition condition, ref EvaluateCo

logBuilder.NewLine("Condition (").AppendSegmentCondition(condition).Append(")");
(error is null
? logBuilder.Append(" evaluates to ").AppendEvaluationResult(result)
? logBuilder.Append(" evaluates to ").AppendConditionResult(result)
: logBuilder.Append(" failed to evaluate"))
.Append(".");

Expand Down
Loading