From cd4b022264ed97f57d6994fc85c425d4e59bb5a7 Mon Sep 17 00:00:00 2001 From: Adam Simon Date: Sat, 1 Jul 2023 09:16:35 +0200 Subject: [PATCH] Add benchmarks for flag evaluation --- .gitignore | 1 + benchmarks/ConfigCat.Client.Benchmarks.sln | 60 ++++ .../ConfigCat.Client.Benchmarks.csproj | 35 ++ .../FlagEvaluationBenchmark.cs | 68 ++++ .../JsonDeserializationBenchmark.cs | 24 +- .../MatrixTestBenchmark.cs | 45 +++ .../ConfigCat.Client.Benchmarks/Program.cs | 11 + benchmarks/ConfigCatClient.Benchmarks.csproj | 35 -- benchmarks/ConfigCatClient.Benchmarks.sln | 39 -- .../NewVersionLib/BenchmarkHelper.Shared.cs | 57 +++ benchmarks/NewVersionLib/BenchmarkHelper.cs | 147 ++++++++ benchmarks/NewVersionLib/ConfigHelper.cs | 13 + benchmarks/NewVersionLib/NewVersionLib.csproj | 31 ++ benchmarks/NewVersionLib/NullLogger.cs | 14 + benchmarks/OldVersionLib/BenchmarkHelper.cs | 103 ++++++ benchmarks/OldVersionLib/OldVersionLib.csproj | 34 ++ .../OldVersionLib/data/sample_v5_old.json | 334 ++++++++++++++++++ benchmarks/Program.cs | 14 - .../ConfigCat.Client.Tests.csproj | 2 +- .../MatrixTestRunner.cs | 118 +------ .../MatrixTestRunnerBase.cs | 142 ++++++++ .../strongname.snk => ConfigCatClient.snk} | Bin src/ConfigCatClient/ConfigCatClient.csproj | 5 +- src/ConfigCatClient/strongname.snk | Bin 596 -> 0 bytes 24 files changed, 1115 insertions(+), 217 deletions(-) create mode 100644 benchmarks/ConfigCat.Client.Benchmarks.sln create mode 100644 benchmarks/ConfigCat.Client.Benchmarks/ConfigCat.Client.Benchmarks.csproj create mode 100644 benchmarks/ConfigCat.Client.Benchmarks/FlagEvaluationBenchmark.cs rename benchmarks/{ => ConfigCat.Client.Benchmarks}/JsonDeserializationBenchmark.cs (57%) create mode 100644 benchmarks/ConfigCat.Client.Benchmarks/MatrixTestBenchmark.cs create mode 100644 benchmarks/ConfigCat.Client.Benchmarks/Program.cs delete mode 100644 benchmarks/ConfigCatClient.Benchmarks.csproj delete mode 100644 benchmarks/ConfigCatClient.Benchmarks.sln create mode 100644 benchmarks/NewVersionLib/BenchmarkHelper.Shared.cs create mode 100644 benchmarks/NewVersionLib/BenchmarkHelper.cs create mode 100644 benchmarks/NewVersionLib/ConfigHelper.cs create mode 100644 benchmarks/NewVersionLib/NewVersionLib.csproj create mode 100644 benchmarks/NewVersionLib/NullLogger.cs create mode 100644 benchmarks/OldVersionLib/BenchmarkHelper.cs create mode 100644 benchmarks/OldVersionLib/OldVersionLib.csproj create mode 100644 benchmarks/OldVersionLib/data/sample_v5_old.json delete mode 100644 benchmarks/Program.cs create mode 100644 src/ConfigCat.Client.Tests/MatrixTestRunnerBase.cs rename src/{ConfigCat.Client.Tests/strongname.snk => ConfigCatClient.snk} (100%) delete mode 100644 src/ConfigCatClient/strongname.snk diff --git a/.gitignore b/.gitignore index 5369e4c1..b79da535 100644 --- a/.gitignore +++ b/.gitignore @@ -288,6 +288,7 @@ __pycache__/ *.xsd.cs # Custom +BenchmarkDotNet.Artifacts*/ coverage.xml .DS_Store .vscode diff --git a/benchmarks/ConfigCat.Client.Benchmarks.sln b/benchmarks/ConfigCat.Client.Benchmarks.sln new file mode 100644 index 00000000..a1d17bf8 --- /dev/null +++ b/benchmarks/ConfigCat.Client.Benchmarks.sln @@ -0,0 +1,60 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33815.320 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConfigCat.Client.Benchmarks", "ConfigCat.Client.Benchmarks\ConfigCat.Client.Benchmarks.csproj", "{B7381881-0709-4F72-AE6C-3778979CD8C1}" + ProjectSection(ProjectDependencies) = postProject + {B51439A6-F230-46E5-9BC3-7E4E9FA841FC} = {B51439A6-F230-46E5-9BC3-7E4E9FA841FC} + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConfigCatClient", "..\src\ConfigCatClient\ConfigCatClient.csproj", "{B51439A6-F230-46E5-9BC3-7E4E9FA841FC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OldVersionLib", "OldVersionLib\OldVersionLib.csproj", "{53015044-8ED1-4F77-BB02-357313F7952A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NewVersionLib", "NewVersionLib\NewVersionLib.csproj", "{30B22E19-6701-4C36-B1F4-72AE24E93CEA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ProjectReferences", "ProjectReferences", "{3B9B9CF8-8D20-423D-A327-60D2D2C77976}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Benchmark|Any CPU = Benchmark|Any CPU + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B7381881-0709-4F72-AE6C-3778979CD8C1}.Benchmark|Any CPU.ActiveCfg = Release|Any CPU + {B7381881-0709-4F72-AE6C-3778979CD8C1}.Benchmark|Any CPU.Build.0 = Release|Any CPU + {B7381881-0709-4F72-AE6C-3778979CD8C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B7381881-0709-4F72-AE6C-3778979CD8C1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B7381881-0709-4F72-AE6C-3778979CD8C1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B7381881-0709-4F72-AE6C-3778979CD8C1}.Release|Any CPU.Build.0 = Release|Any CPU + {B51439A6-F230-46E5-9BC3-7E4E9FA841FC}.Benchmark|Any CPU.ActiveCfg = Benchmark|Any CPU + {B51439A6-F230-46E5-9BC3-7E4E9FA841FC}.Benchmark|Any CPU.Build.0 = Benchmark|Any CPU + {B51439A6-F230-46E5-9BC3-7E4E9FA841FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B51439A6-F230-46E5-9BC3-7E4E9FA841FC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B51439A6-F230-46E5-9BC3-7E4E9FA841FC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B51439A6-F230-46E5-9BC3-7E4E9FA841FC}.Release|Any CPU.Build.0 = Release|Any CPU + {53015044-8ED1-4F77-BB02-357313F7952A}.Benchmark|Any CPU.ActiveCfg = Release|Any CPU + {53015044-8ED1-4F77-BB02-357313F7952A}.Benchmark|Any CPU.Build.0 = Release|Any CPU + {53015044-8ED1-4F77-BB02-357313F7952A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {53015044-8ED1-4F77-BB02-357313F7952A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {53015044-8ED1-4F77-BB02-357313F7952A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {53015044-8ED1-4F77-BB02-357313F7952A}.Release|Any CPU.Build.0 = Release|Any CPU + {30B22E19-6701-4C36-B1F4-72AE24E93CEA}.Benchmark|Any CPU.ActiveCfg = Release|Any CPU + {30B22E19-6701-4C36-B1F4-72AE24E93CEA}.Benchmark|Any CPU.Build.0 = Release|Any CPU + {30B22E19-6701-4C36-B1F4-72AE24E93CEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {30B22E19-6701-4C36-B1F4-72AE24E93CEA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {30B22E19-6701-4C36-B1F4-72AE24E93CEA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {30B22E19-6701-4C36-B1F4-72AE24E93CEA}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {B51439A6-F230-46E5-9BC3-7E4E9FA841FC} = {3B9B9CF8-8D20-423D-A327-60D2D2C77976} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {71FC06CD-80AD-4090-863E-1965313C9027} + EndGlobalSection +EndGlobal diff --git a/benchmarks/ConfigCat.Client.Benchmarks/ConfigCat.Client.Benchmarks.csproj b/benchmarks/ConfigCat.Client.Benchmarks/ConfigCat.Client.Benchmarks.csproj new file mode 100644 index 00000000..d6560026 --- /dev/null +++ b/benchmarks/ConfigCat.Client.Benchmarks/ConfigCat.Client.Benchmarks.csproj @@ -0,0 +1,35 @@ + + + + Exe + net48;net6.0 + 10.0 + enable + nullable + true + ..\..\src\ConfigCatClient.snk + + + + + + + + + + Configuration=Benchmark + from_project + + + + + + + + + from_nuget + + + + + diff --git a/benchmarks/ConfigCat.Client.Benchmarks/FlagEvaluationBenchmark.cs b/benchmarks/ConfigCat.Client.Benchmarks/FlagEvaluationBenchmark.cs new file mode 100644 index 00000000..91fd1802 --- /dev/null +++ b/benchmarks/ConfigCat.Client.Benchmarks/FlagEvaluationBenchmark.cs @@ -0,0 +1,68 @@ +extern alias from_nuget; +extern alias from_project; + +using System; +using BenchmarkDotNet.Attributes; + +namespace ConfigCat.Client.Benchmarks; + +[MemoryDiagnoser] +public class FlagEvaluationBenchmark +{ + private object evaluationServicesOld = null!; + private from_nuget::ConfigCat.Client.User userOld = null!; + + private object evaluationServicesNew = null!; + private from_project::ConfigCat.Client.User userNew = null!; + + [GlobalSetup] + public void Setup() + { + Environment.CurrentDirectory = AppContext.BaseDirectory; + + this.evaluationServicesOld = Old.BenchmarkHelper.CreateEvaluationServices(LogInfo); + this.userOld = new("Cat") { Email = "cat@configcat.com", Custom = { ["Version"] = "1.1.1", ["Number"] = "1" } }; + + this.evaluationServicesNew = New.BenchmarkHelper.CreateEvaluationServices(LogInfo); + this.userNew = new("Cat") { Email = "cat@configcat.com", Custom = { ["Version"] = "1.1.1", ["Number"] = "1" } }; + } + + [Params(false, true)] + public bool LogInfo { get; set; } + + [Benchmark] + public object Basic_ConfigV5() + { + return Old.BenchmarkHelper.Evaluate(this.evaluationServicesOld, "basicFlag", false); + } + + [Benchmark] + public object Basic_ConfigV6() + { + return New.BenchmarkHelper.Evaluate(this.evaluationServicesNew, "basicFlag", false); + } + + [Benchmark] + public object Complex_ConfigV5() + { + return Old.BenchmarkHelper.Evaluate(this.evaluationServicesOld, "complexFlag", "", this.userOld); + } + + [Benchmark] + public object Complex_ConfigV6() + { + return New.BenchmarkHelper.Evaluate(this.evaluationServicesNew, "complexFlag", "", this.userNew); + } + + [Benchmark] + public object All_ConfigV5() + { + return Old.BenchmarkHelper.EvaluateAll(this.evaluationServicesOld, this.userOld); + } + + [Benchmark] + public object All_ConfigV6() + { + return New.BenchmarkHelper.EvaluateAll(this.evaluationServicesNew, this.userNew); + } +} diff --git a/benchmarks/JsonDeserializationBenchmark.cs b/benchmarks/ConfigCat.Client.Benchmarks/JsonDeserializationBenchmark.cs similarity index 57% rename from benchmarks/JsonDeserializationBenchmark.cs rename to benchmarks/ConfigCat.Client.Benchmarks/JsonDeserializationBenchmark.cs index 0010593a..36900bbf 100644 --- a/benchmarks/JsonDeserializationBenchmark.cs +++ b/benchmarks/ConfigCat.Client.Benchmarks/JsonDeserializationBenchmark.cs @@ -1,24 +1,24 @@ -extern alias from_nuget; +extern alias from_nuget; extern alias from_project; using BenchmarkDotNet.Attributes; using System; -namespace ConfigCatClient.Benchmarks; +namespace ConfigCat.Client.Benchmarks; [MemoryDiagnoser] public class JsonDeserializationBenchmark { - private readonly from_project::ConfigCat.Client.IConfigCatClient newClient = from_project::ConfigCat.Client.ConfigCatClientBuilder - .Initialize("rv3YCMKenkaM7xkOCVQfeg/-I_w49WSQUWdZypPPM4Yyg") - .WithManualPoll() - .WithBaseUrl(new Uri("https://test-cdn-global.configcat.com")) - .Create(); + private readonly from_project::ConfigCat.Client.IConfigCatClient newClient = from_project::ConfigCat.Client.ConfigCatClient.Get("rv3YCMKenkaM7xkOCVQfeg/-I_w49WSQUWdZypPPM4Yyg", o => + { + o.PollingMode = from_project::ConfigCat.Client.PollingModes.ManualPoll; + o.BaseUrl = new Uri("https://test-cdn-global.configcat.com"); + }); - private readonly from_nuget::ConfigCat.Client.IConfigCatClient oldClient = from_nuget::ConfigCat.Client.ConfigCatClientBuilder - .Initialize("rv3YCMKenkaM7xkOCVQfeg/-I_w49WSQUWdZypPPM4Yyg") - .WithManualPoll() - .WithBaseUrl(new Uri("https://test-cdn-global.configcat.com")) - .Create(); + private readonly from_nuget::ConfigCat.Client.IConfigCatClient oldClient = from_nuget::ConfigCat.Client.ConfigCatClient.Get("rv3YCMKenkaM7xkOCVQfeg/-I_w49WSQUWdZypPPM4Yyg", o => + { + o.PollingMode = from_nuget::ConfigCat.Client.PollingModes.ManualPoll; + o.BaseUrl = new Uri("https://test-cdn-global.configcat.com"); + }); private readonly from_project::ConfigCat.Client.User newUser = new("test@test.com"); private readonly from_nuget::ConfigCat.Client.User oldUser = new("test@test.com"); diff --git a/benchmarks/ConfigCat.Client.Benchmarks/MatrixTestBenchmark.cs b/benchmarks/ConfigCat.Client.Benchmarks/MatrixTestBenchmark.cs new file mode 100644 index 00000000..6d8fa245 --- /dev/null +++ b/benchmarks/ConfigCat.Client.Benchmarks/MatrixTestBenchmark.cs @@ -0,0 +1,45 @@ +using System; +using BenchmarkDotNet.Attributes; + +namespace ConfigCat.Client.Benchmarks; + +[MemoryDiagnoser] +public class MatrixTestBenchmark +{ + private Old.MatrixTestRunnerBase testRunnerOld = null!; + private object evaluationServicesOld = null!; + + private New.MatrixTestRunnerBase testRunnerNew = null!; + private object evaluationServicesNew = null!; + + private object?[][] tests = null!; + + [GlobalSetup] + public void Setup() + { + Environment.CurrentDirectory = AppContext.BaseDirectory; + + this.testRunnerOld = new(); + this.evaluationServicesOld = Old.BenchmarkHelper.CreateEvaluationServices(LogInfo); + + this.testRunnerNew = new(); + this.evaluationServicesNew = New.BenchmarkHelper.CreateEvaluationServices(LogInfo); + + this.tests = New.BenchmarkHelper.GetMatrixTests(); + } + + [Params(false, true)] + public bool LogInfo { get; set; } + + [Benchmark] + public int MatrixTests_ConfigV5() + { + return Old.BenchmarkHelper.RunAllMatrixTests(this.testRunnerOld, this.evaluationServicesOld, this.tests); + } + + [Benchmark] + public int MatrixTests_ConfigV6() + { + return New.BenchmarkHelper.RunAllMatrixTests(this.testRunnerNew, this.evaluationServicesNew, this.tests); + } +} diff --git a/benchmarks/ConfigCat.Client.Benchmarks/Program.cs b/benchmarks/ConfigCat.Client.Benchmarks/Program.cs new file mode 100644 index 00000000..a84eebc9 --- /dev/null +++ b/benchmarks/ConfigCat.Client.Benchmarks/Program.cs @@ -0,0 +1,11 @@ +using BenchmarkDotNet.Running; + +namespace ConfigCatClient.Benchmarks; + +internal class Program +{ + private static void Main(string[] args) + { + BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); + } +} diff --git a/benchmarks/ConfigCatClient.Benchmarks.csproj b/benchmarks/ConfigCatClient.Benchmarks.csproj deleted file mode 100644 index 60965e3e..00000000 --- a/benchmarks/ConfigCatClient.Benchmarks.csproj +++ /dev/null @@ -1,35 +0,0 @@ - - - - Exe - net6.0 - Debug;Release;Benchmark - - - - true - - - - - - - - - - - ..\src\ConfigCatClient\bin\Benchmark\netstandard2.1\ConfigCat.Client.Benchmark.dll - from_project - true - - - - - - - from_nuget - - - - - diff --git a/benchmarks/ConfigCatClient.Benchmarks.sln b/benchmarks/ConfigCatClient.Benchmarks.sln deleted file mode 100644 index 07a8d758..00000000 --- a/benchmarks/ConfigCatClient.Benchmarks.sln +++ /dev/null @@ -1,39 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30907.101 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConfigCatClient.Benchmarks", "ConfigCatClient.Benchmarks.csproj", "{B7381881-0709-4F72-AE6C-3778979CD8C1}" - ProjectSection(ProjectDependencies) = postProject - {B51439A6-F230-46E5-9BC3-7E4E9FA841FC} = {B51439A6-F230-46E5-9BC3-7E4E9FA841FC} - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConfigCatClient", "..\src\ConfigCatClient\ConfigCatClient.csproj", "{B51439A6-F230-46E5-9BC3-7E4E9FA841FC}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Benchmark|Any CPU = Benchmark|Any CPU - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B7381881-0709-4F72-AE6C-3778979CD8C1}.Benchmark|Any CPU.ActiveCfg = Benchmark|Any CPU - {B7381881-0709-4F72-AE6C-3778979CD8C1}.Benchmark|Any CPU.Build.0 = Benchmark|Any CPU - {B7381881-0709-4F72-AE6C-3778979CD8C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B7381881-0709-4F72-AE6C-3778979CD8C1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B7381881-0709-4F72-AE6C-3778979CD8C1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B7381881-0709-4F72-AE6C-3778979CD8C1}.Release|Any CPU.Build.0 = Release|Any CPU - {B51439A6-F230-46E5-9BC3-7E4E9FA841FC}.Benchmark|Any CPU.ActiveCfg = Benchmark|Any CPU - {B51439A6-F230-46E5-9BC3-7E4E9FA841FC}.Benchmark|Any CPU.Build.0 = Benchmark|Any CPU - {B51439A6-F230-46E5-9BC3-7E4E9FA841FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B51439A6-F230-46E5-9BC3-7E4E9FA841FC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B51439A6-F230-46E5-9BC3-7E4E9FA841FC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B51439A6-F230-46E5-9BC3-7E4E9FA841FC}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {71FC06CD-80AD-4090-863E-1965313C9027} - EndGlobalSection -EndGlobal diff --git a/benchmarks/NewVersionLib/BenchmarkHelper.Shared.cs b/benchmarks/NewVersionLib/BenchmarkHelper.Shared.cs new file mode 100644 index 00000000..c9dad514 --- /dev/null +++ b/benchmarks/NewVersionLib/BenchmarkHelper.Shared.cs @@ -0,0 +1,57 @@ +using System.Linq; +using ConfigCat.Client.Evaluation; + +#if BENCHMARK_OLD +namespace ConfigCat.Client.Benchmarks.Old; +#else +namespace ConfigCat.Client.Benchmarks.New; +#endif + +internal class EvaluationServices +{ + public EvaluationServices(bool logInfo) + { + Logger = new LoggerWrapper(new NullLogger { LogLevel = logInfo ? LogLevel.Info : LogLevel.Warning }); + Evaluator = new RolloutEvaluator(Logger); + } + + public LoggerWrapper Logger { get; } + public RolloutEvaluator Evaluator { get; } +} + +public static partial class BenchmarkHelper +{ + public static object CreateEvaluationServices(bool logInfo) => new EvaluationServices(logInfo); + + public static object?[][] GetMatrixTests() + where TDescriptor : IMatrixTestDescriptor, new() + { + return MatrixTestRunnerBase.GetTests().ToArray(); + } + + public static bool RunMatrixTest(this MatrixTestRunnerBase runner, object evaluationServices, string settingKey, string expectedReturnValue, User? user = null) + where TDescriptor : IMatrixTestDescriptor, new() + { + var services = (EvaluationServices)evaluationServices; + return runner.RunTest(services.Evaluator, services.Logger, settingKey, expectedReturnValue, user); + } + + public static int RunAllMatrixTests(this MatrixTestRunnerBase runner, object evaluationServices, object?[][] tests) + where TDescriptor : IMatrixTestDescriptor, new() + { + var services = (EvaluationServices)evaluationServices; + return runner.RunAllTests(services.Evaluator, services.Logger, tests); + } + + public static EvaluationDetails Evaluate(object evaluationServices, string key, T defaultValue, User? user = null) + { + var services = (EvaluationServices)evaluationServices; + return services.Evaluator.Evaluate(Config.Settings, key, defaultValue, user, remoteConfig: null, services.Logger); + } + + public static EvaluationDetails[] EvaluateAll(object evaluationServices, User? user = null) + { + var services = (EvaluationServices)evaluationServices; + return services.Evaluator.EvaluateAll(Config.Settings, user, remoteConfig: null, services.Logger, "empty array", out _); + } +} diff --git a/benchmarks/NewVersionLib/BenchmarkHelper.cs b/benchmarks/NewVersionLib/BenchmarkHelper.cs new file mode 100644 index 00000000..b3f94ef5 --- /dev/null +++ b/benchmarks/NewVersionLib/BenchmarkHelper.cs @@ -0,0 +1,147 @@ +using System; + +namespace ConfigCat.Client.Benchmarks.New; + +public static partial class BenchmarkHelper +{ + public class BasicMatrixTestsDescriptor : IMatrixTestDescriptor + { + public string SampleJsonFileName => "sample_v5.json"; + public string MatrixResultFileName => "testmatrix.csv"; + } + + private static readonly Config Config = new Func(() => + { + var config = new Config + { + Preferences = new Preferences + { + Salt = "LKQu1a62agfNnWuGwA8cZglf4x0yZSbY2En7WQn5dWw" + }, + Settings = + { + ["basicFlag"] = new Setting + { + SettingType = SettingType.Boolean, + Value = new SettingValue { BoolValue = true }, + }, + ["complexFlag"] = new Setting + { + SettingType = SettingType.String, + TargetingRules = new[] + { + new TargetingRule + { + Conditions = new[] + { + new ConditionWrapper + { + ComparisonCondition = new ComparisonCondition() + { + ComparisonAttribute = nameof(User.Identifier), + Comparator = Comparator.SensitiveOneOf, + StringListValue = new[] + { + "61418c941ecda8031d08ab86ec821e676fde7b6a59cd16b1e7191503c2f8297d", + "2ebea0310612c4c40d183b0c123d9bd425cf54f1e101f42858e701b5077cba01" + } + } + }, + }, + SimpleValue = new SimpleSettingValue { Value = new SettingValue { StringValue = "a" } }, + }, + new TargetingRule + { + Conditions = new[] + { + new ConditionWrapper + { + ComparisonCondition = new ComparisonCondition() + { + ComparisonAttribute = nameof(User.Email), + Comparator = Comparator.Contains, + StringListValue = new[] { "@example.com" } + } + }, + }, + SimpleValue = new SimpleSettingValue { Value = new SettingValue { StringValue = "b" } }, + }, + new TargetingRule + { + Conditions = new[] + { + new ConditionWrapper + { + ComparisonCondition = new ComparisonCondition() + { + ComparisonAttribute = "Version", + Comparator = Comparator.SemVerOneOf, + StringListValue = new[] { "1.0.0", "2.0.0" } + } + }, + }, + SimpleValue = new SimpleSettingValue { Value = new SettingValue { StringValue = "c" } }, + }, + new TargetingRule + { + Conditions = new[] + { + new ConditionWrapper + { + ComparisonCondition = new ComparisonCondition() + { + ComparisonAttribute = "Version", + Comparator = Comparator.SemVerGreaterThan, + StringValue = "3.0.0" + } + }, + }, + SimpleValue = new SimpleSettingValue { Value = new SettingValue { StringValue = "d" } }, + }, + new TargetingRule + { + Conditions = new[] + { + new ConditionWrapper + { + ComparisonCondition = new ComparisonCondition() + { + ComparisonAttribute = "Number", + Comparator = Comparator.NumberGreaterThan, + DoubleValue = 3.14 + } + }, + }, + SimpleValue = new SimpleSettingValue { Value = new SettingValue { StringValue = "e" } }, + }, + new TargetingRule + { + PercentageOptions = new[] + { + new PercentageOption + { + Percentage = 20, + Value = new SettingValue { StringValue = "p20" } + }, + new PercentageOption + { + Percentage = 30, + Value = new SettingValue { StringValue = "p30" } + }, + new PercentageOption + { + Percentage = 50, + Value = new SettingValue { StringValue = "p50" } + }, + } + }, + }, + Value = new SettingValue { StringValue = "fallback" } + } + } + }; + + config.OnDeserialized(); + return config; + })(); +} diff --git a/benchmarks/NewVersionLib/ConfigHelper.cs b/benchmarks/NewVersionLib/ConfigHelper.cs new file mode 100644 index 00000000..b4a9de13 --- /dev/null +++ b/benchmarks/NewVersionLib/ConfigHelper.cs @@ -0,0 +1,13 @@ +using System.IO; + +namespace ConfigCat.Client.Tests.Helpers; + +internal static class ConfigHelper +{ + public static string GetSampleJson(string fileName) + { + using Stream stream = File.OpenRead(Path.Combine("data", fileName)); + using StreamReader reader = new(stream); + return reader.ReadToEnd(); + } +} diff --git a/benchmarks/NewVersionLib/NewVersionLib.csproj b/benchmarks/NewVersionLib/NewVersionLib.csproj new file mode 100644 index 00000000..c8fc9052 --- /dev/null +++ b/benchmarks/NewVersionLib/NewVersionLib.csproj @@ -0,0 +1,31 @@ + + + + ConfigCatClientBenchmarks + ConfigCat.Client.Benchmarks.New + net48;net6.0 + 10.0 + enable + nullable + true + ..\..\src\ConfigCatClient.snk + BENCHMARK_NEW;$(DefineConstants) + + + + + Configuration=Benchmark + + + + + + + + + + PreserveNewest + + + + diff --git a/benchmarks/NewVersionLib/NullLogger.cs b/benchmarks/NewVersionLib/NullLogger.cs new file mode 100644 index 00000000..f75a4162 --- /dev/null +++ b/benchmarks/NewVersionLib/NullLogger.cs @@ -0,0 +1,14 @@ +using System; + +#if BENCHMARK_OLD +namespace ConfigCat.Client.Benchmarks.Old; +#else +namespace ConfigCat.Client.Benchmarks.New; +#endif + +public class NullLogger : IConfigCatLogger +{ + public LogLevel LogLevel { get; set; } + + public void Log(LogLevel level, LogEventId eventId, ref FormattableLogMessage message, Exception? exception = null) { } +} diff --git a/benchmarks/OldVersionLib/BenchmarkHelper.cs b/benchmarks/OldVersionLib/BenchmarkHelper.cs new file mode 100644 index 00000000..74b69629 --- /dev/null +++ b/benchmarks/OldVersionLib/BenchmarkHelper.cs @@ -0,0 +1,103 @@ +using System.Reflection; +using System.Text.Json; + +namespace ConfigCat.Client.Benchmarks.Old; + +public static partial class BenchmarkHelper +{ + public class BasicMatrixTestsDescriptor : IMatrixTestDescriptor + { + public string SampleJsonFileName => "sample_v5_old.json"; + public string MatrixResultFileName => "testmatrix.csv"; + } + + private static readonly SettingsWithPreferences Config = new SettingsWithPreferences + { + Settings = + { + ["basicFlag"] = CreateSetting(SettingType.Boolean, JsonDocument.Parse("true").RootElement), + ["complexFlag"] = CreateSetting(SettingType.String, JsonDocument.Parse("\"fallback\"").RootElement, + new[] + { + new RolloutRule + { + Order = 0, + ComparisonAttribute = nameof(User.Identifier), + Comparator = Comparator.SensitiveOneOf, + ComparisonValue = "68d93aa74a0aa1664f65ad6c0515f24769b15c84,8409e4e5d27a1465165012b03b2606f0e5b08250", + Value = JsonDocument.Parse("\"a\"").RootElement, + }, + new RolloutRule + { + Order = 1, + ComparisonAttribute = nameof(User.Email), + Comparator = Comparator.Contains, + ComparisonValue = "@example.com", + Value = JsonDocument.Parse("\"b\"").RootElement, + }, + new RolloutRule + { + Order = 2, + ComparisonAttribute = "Version", + Comparator = Comparator.SemVerIn, + ComparisonValue = "1.0.0, 2.0.0", + Value = JsonDocument.Parse("\"c\"").RootElement, + }, + new RolloutRule + { + Order = 3, + ComparisonAttribute = "Version", + Comparator = Comparator.SemVerGreaterThan, + ComparisonValue = "3.0.0", + Value = JsonDocument.Parse("\"d\"").RootElement, + }, + new RolloutRule + { + Order = 4, + ComparisonAttribute = "Number", + Comparator = Comparator.NumberGreaterThan, + ComparisonValue = "3.14", + Value = JsonDocument.Parse("\"e\"").RootElement, + }, + }, + new[] + { + new RolloutPercentageItem + { + Percentage = 20, + Value = JsonDocument.Parse("\"p20\"").RootElement + }, + new RolloutPercentageItem + { + Percentage = 30, + Value = JsonDocument.Parse("\"p30\"").RootElement + }, + new RolloutPercentageItem + { + Percentage = 50, + Value = JsonDocument.Parse("\"p50\"").RootElement + }, + }) + } + }; + + private static Setting CreateSetting(SettingType settingType, JsonElement value, RolloutRule[]? targetingRules = null, RolloutPercentageItem[]? percentageOptions = null) + { + var setting = new Setting + { + SettingType = settingType, + Value = value, + }; + + SetPrivatePropertyValue(setting, nameof(setting.RolloutRules), targetingRules); + SetPrivatePropertyValue(setting, nameof(setting.RolloutPercentageItems), percentageOptions); + + return setting; + } + + private static void SetPrivatePropertyValue(object obj, string propertyName, object? value) + { + var type = obj.GetType(); + type.InvokeMember(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, null, obj, new[] { value }); + } +} diff --git a/benchmarks/OldVersionLib/OldVersionLib.csproj b/benchmarks/OldVersionLib/OldVersionLib.csproj new file mode 100644 index 00000000..670d9cf3 --- /dev/null +++ b/benchmarks/OldVersionLib/OldVersionLib.csproj @@ -0,0 +1,34 @@ + + + + + ConfigCatClientTests + ConfigCat.Client.Benchmarks.New + net48;net6.0 + 10.0 + enable + nullable + true + ..\..\src\ConfigCatClient.snk + BENCHMARK_OLD;$(DefineConstants) + + + + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/benchmarks/OldVersionLib/data/sample_v5_old.json b/benchmarks/OldVersionLib/data/sample_v5_old.json new file mode 100644 index 00000000..253e5320 --- /dev/null +++ b/benchmarks/OldVersionLib/data/sample_v5_old.json @@ -0,0 +1,334 @@ +{ + "f": { + "stringDefaultCat": { + "v": "Cat", + "t": 1, + "p": [], + "r": [] + }, + "stringIsInDogDefaultCat": { + "v": "Cat", + "t": 1, + "p": [], + "r": [ + { + "o": 0, + "a": "Email", + "t": 0, + "c": "a@configcat.com, b@configcat.com", + "v": "Dog" + }, + { + "o": 1, + "a": "Custom1", + "t": 0, + "c": "admin", + "v": "Dog" + } + ] + }, + "stringIsNotInDogDefaultCat": { + "v": "Cat", + "t": 1, + "p": [], + "r": [ + { + "o": 0, + "a": "Email", + "t": 1, + "c": "a@configcat.com,b@configcat.com", + "v": "Dog" + } + ] + }, + "stringContainsDogDefaultCat": { + "v": "Cat", + "t": 1, + "p": [], + "r": [ + { + "o": 0, + "a": "Email", + "t": 2, + "c": "@configcat.com", + "v": "Dog" + } + ] + }, + "stringNotContainsDogDefaultCat": { + "v": "Cat", + "t": 1, + "p": [], + "r": [ + { + "o": 0, + "a": "Email", + "t": 3, + "c": "@configcat.com", + "v": "Dog" + } + ] + }, + "string25Cat25Dog25Falcon25Horse": { + "v": "Chicken", + "t": 1, + "p": [ + { + "o": 0, + "v": "Cat", + "p": 25 + }, + { + "o": 1, + "v": "Dog", + "p": 25 + }, + { + "o": 2, + "v": "Falcon", + "p": 25 + }, + { + "o": 3, + "v": "Horse", + "p": 25 + } + ], + "r": [] + }, + "string75Cat0Dog25Falcon0Horse": { + "v": "Chicken", + "t": 1, + "p": [ + { + "o": 0, + "v": "Cat", + "p": 75 + }, + { + "o": 1, + "v": "Dog", + "p": 0 + }, + { + "o": 2, + "v": "Falcon", + "p": 25 + }, + { + "o": 3, + "v": "Horse", + "p": 0 + } + ], + "r": [] + }, + "string25Cat25Dog25Falcon25HorseAdvancedRules": { + "v": "Chicken", + "t": 1, + "p": [ + { + "o": 0, + "v": "Cat", + "p": 25 + }, + { + "o": 1, + "v": "Dog", + "p": 25 + }, + { + "o": 2, + "v": "Falcon", + "p": 25 + }, + { + "o": 3, + "v": "Horse", + "p": 25 + } + ], + "r": [ + { + "o": 0, + "a": "Country", + "t": 0, + "c": "Hungary, United Kingdom", + "v": "Dolphin" + }, + { + "o": 1, + "a": "Custom1", + "t": 2, + "c": "admi", + "v": "Lion" + }, + { + "o": 2, + "a": "Email", + "t": 2, + "c": "@configcat.com", + "v": "Kitten" + } + ] + }, + "boolDefaultTrue": { + "v": true, + "t": 0, + "p": [], + "r": [] + }, + "boolDefaultFalse": { + "v": false, + "t": 0, + "p": [], + "r": [] + }, + "bool30TrueAdvancedRules": { + "v": true, + "t": 0, + "p": [ + { + "o": 0, + "v": true, + "p": 30 + }, + { + "o": 1, + "v": false, + "p": 70 + } + ], + "r": [ + { + "o": 0, + "a": "Email", + "t": 0, + "c": "a@configcat.com, b@configcat.com", + "v": false + }, + { + "o": 1, + "a": "Country", + "t": 2, + "c": "United", + "v": false + } + ] + }, + "integer25One25Two25Three25FourAdvancedRules": { + "v": -1, + "t": 2, + "p": [ + { + "o": 0, + "v": 1, + "p": 25 + }, + { + "o": 1, + "v": 2, + "p": 25 + }, + { + "o": 2, + "v": 3, + "p": 25 + }, + { + "o": 3, + "v": 4, + "p": 25 + } + ], + "r": [ + { + "o": 0, + "a": "Email", + "t": 2, + "c": "@configcat.com", + "v": 5 + } + ] + }, + "integerDefaultOne": { + "v": 1, + "t": 2, + "p": [], + "r": [] + }, + "doubleDefaultPi": { + "v": 3.1415, + "t": 3, + "p": [], + "r": [] + }, + "double25Pi25E25Gr25Zero": { + "v": -1.0, + "t": 3, + "p": [ + { + "o": 0, + "v": 3.1415, + "p": 25 + }, + { + "o": 1, + "v": 2.7182, + "p": 25 + }, + { + "o": 2, + "v": 1.61803, + "p": 25 + }, + { + "o": 3, + "v": 0.0, + "p": 25 + } + ], + "r": [ + { + "o": 0, + "a": "Email", + "t": 2, + "c": "@configcat.com", + "v": 5.561 + } + ] + }, + "keySampleText": { + "v": "Cat", + "t": 1, + "p": [ + { + "o": 0, + "v": "Falcon", + "p": 50 + }, + { + "o": 1, + "v": "Horse", + "p": 50 + } + ], + "r": [ + { + "o": 0, + "a": "Country", + "t": 0, + "c": "Hungary,Bahamas", + "v": "Dog" + }, + { + "o": 1, + "a": "SubscriptionType", + "t": 0, + "c": "unlimited", + "v": "Lion" + } + ] + } + } +} \ No newline at end of file diff --git a/benchmarks/Program.cs b/benchmarks/Program.cs deleted file mode 100644 index 527bf545..00000000 --- a/benchmarks/Program.cs +++ /dev/null @@ -1,14 +0,0 @@ -using BenchmarkDotNet.Running; -using System; - -namespace ConfigCatClient.Benchmarks; - -internal class Program -{ - private static void Main(string[] args) - { - BenchmarkRunner.Run(); - - Console.ReadKey(); - } -} diff --git a/src/ConfigCat.Client.Tests/ConfigCat.Client.Tests.csproj b/src/ConfigCat.Client.Tests/ConfigCat.Client.Tests.csproj index 3a688b8a..9fc3719d 100644 --- a/src/ConfigCat.Client.Tests/ConfigCat.Client.Tests.csproj +++ b/src/ConfigCat.Client.Tests/ConfigCat.Client.Tests.csproj @@ -8,7 +8,7 @@ 10.0 enable nullable - strongname.snk + ..\ConfigCatClient.snk diff --git a/src/ConfigCat.Client.Tests/MatrixTestRunner.cs b/src/ConfigCat.Client.Tests/MatrixTestRunner.cs index a4638120..cd8a2b45 100644 --- a/src/ConfigCat.Client.Tests/MatrixTestRunner.cs +++ b/src/ConfigCat.Client.Tests/MatrixTestRunner.cs @@ -1,125 +1,17 @@ using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using ConfigCat.Client.Evaluation; -using ConfigCat.Client.Tests.Helpers; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace ConfigCat.Client.Tests; -public interface IMatrixTestDescriptor +public class MatrixTestRunner : MatrixTestRunnerBase + where TDescriptor : IMatrixTestDescriptor, new() { - public string SampleJsonFileName { get; } - public string MatrixResultFileName { get; } -} - -public class MatrixTestRunner where TDescriptor : IMatrixTestDescriptor, new() -{ - private static readonly Lazy> DefaultLazy = new(() => new MatrixTestRunner(), isThreadSafe: true); - public static MatrixTestRunner Default => DefaultLazy.Value; - - public static readonly TDescriptor DescriptorInstance = new(); - - private protected readonly Dictionary config; - - public MatrixTestRunner() - { - this.config = ConfigHelper.GetSampleJson(DescriptorInstance.SampleJsonFileName).Deserialize()!.Settings; - } + private static readonly Lazy> DefaultLazy = new(() => new MatrixTestRunner(), isThreadSafe: true); + public static MatrixTestRunnerBase Default => DefaultLazy.Value; - public static IEnumerable GetTests() - { - var resultFilePath = Path.Combine("data", DescriptorInstance.MatrixResultFileName); - using var reader = new StreamReader(resultFilePath); - var header = reader.ReadLine()!; - - var columns = header.Split(new[] { ';' }); - - while (!reader.EndOfStream) - { - var rawline = reader.ReadLine(); - - if (string.IsNullOrEmpty(rawline)) - continue; - - var row = rawline.Split(new[] { ';' }); - - string? userId = null, userEmail = null, userCountry = null, userCustomAttributeName = null, userCustomAttributeValue = null; - if (row[0] != "##null##") - { - userId = row[0]; - userEmail = row[1] is "" or "##null##" ? null : row[1]; - userCountry = row[2] is "" or "##null##" ? null : row[2]; - if (row[3] is not ("" or "##null##")) - { - userCustomAttributeName = columns[3]; - userCustomAttributeValue = row[3]; - } - } - - for (var i = 4; i < columns.Length; i++) - { - yield return new[] - { - DescriptorInstance.SampleJsonFileName, columns[i], row[i], - userId, userEmail, userCountry, userCustomAttributeName, userCustomAttributeValue - }; - } - } - } - - protected virtual bool AssertValue(string expected, Func parse, T actual, string keyName, string? userId) + protected override bool AssertValue(string expected, Func parse, T actual, string keyName, string? userId) { Assert.AreEqual(parse(expected), actual, $"jsonFileName: {DescriptorInstance.SampleJsonFileName} | keyName: {keyName} | userId: {userId}"); return true; } - - internal bool RunTest(IRolloutEvaluator evaluator, LoggerWrapper logger, string settingKey, string expectedReturnValue, User? user = null) - { - if (settingKey.StartsWith("bool", StringComparison.OrdinalIgnoreCase)) - { - var actual = evaluator.Evaluate(this.config, settingKey, false, user, null, logger).Value; - - return AssertValue(expectedReturnValue, static e => bool.Parse(e), actual, settingKey, user?.Identifier); - } - else if (settingKey.StartsWith("double", StringComparison.OrdinalIgnoreCase)) - { - var actual = evaluator.Evaluate(this.config, settingKey, double.NaN, user, null, logger).Value; - - return AssertValue(expectedReturnValue, static e => double.Parse(e, CultureInfo.InvariantCulture), actual, settingKey, user?.Identifier); - } - else if (settingKey.StartsWith("integer", StringComparison.OrdinalIgnoreCase)) - { - var actual = evaluator.Evaluate(this.config, settingKey, int.MinValue, user, null, logger).Value; - - return AssertValue(expectedReturnValue, static e => int.Parse(e, CultureInfo.InvariantCulture), actual, settingKey, user?.Identifier); - } - else if (settingKey.StartsWith("string", StringComparison.OrdinalIgnoreCase)) - { - var actual = evaluator.Evaluate(this.config, settingKey, string.Empty, user, null, logger).Value; - - return AssertValue(expectedReturnValue, static e => e, actual, settingKey, user?.Identifier); - } - else - { - var actual = evaluator.Evaluate(this.config, settingKey, (object?)null, user, null, logger).Value; - - return AssertValue(expectedReturnValue, static e => e, Convert.ToString(actual, CultureInfo.InvariantCulture), settingKey, user?.Identifier); - } - } - - internal bool RunTest(IRolloutEvaluator evaluator, LoggerWrapper logger, string settingKey, string expectedReturnValue, - string? userId, string? userEmail, string? userCountry, string? userCustomAttributeName, string? userCustomAttributeValue) - { - User? user = null; - if (userId is not null) - { - user = new User(userId) { Email = userEmail, Country = userCountry }; - if (userCustomAttributeValue is not null) - user.Custom[userCustomAttributeName!] = userCustomAttributeValue; - } - - return RunTest(evaluator, logger, settingKey, expectedReturnValue, user); - } } diff --git a/src/ConfigCat.Client.Tests/MatrixTestRunnerBase.cs b/src/ConfigCat.Client.Tests/MatrixTestRunnerBase.cs new file mode 100644 index 00000000..ca84d05f --- /dev/null +++ b/src/ConfigCat.Client.Tests/MatrixTestRunnerBase.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using ConfigCat.Client.Evaluation; +using ConfigCat.Client.Tests.Helpers; + +#if BENCHMARK_OLD +using Config = ConfigCat.Client.SettingsWithPreferences; +#endif + +#if BENCHMARK_OLD +namespace ConfigCat.Client.Benchmarks.Old; +#elif BENCHMARK_NEW +namespace ConfigCat.Client.Benchmarks.New; +#else +namespace ConfigCat.Client.Tests; +#endif + +// NOTE: These types are intentionally placed into a separate source file because it's also used in the benchmark project. + +public interface IMatrixTestDescriptor +{ + public string SampleJsonFileName { get; } + public string MatrixResultFileName { get; } +} + +public class MatrixTestRunnerBase where TDescriptor : IMatrixTestDescriptor, new() +{ + public static readonly TDescriptor DescriptorInstance = new(); + + private protected readonly Dictionary config; + + public MatrixTestRunnerBase() + { + this.config = ConfigHelper.GetSampleJson(DescriptorInstance.SampleJsonFileName).Deserialize()!.Settings; + } + + public static IEnumerable GetTests() + { + var resultFilePath = Path.Combine("data", DescriptorInstance.MatrixResultFileName); + using var reader = new StreamReader(resultFilePath); + var header = reader.ReadLine()!; + + var columns = header.Split(new[] { ';' }); + + while (!reader.EndOfStream) + { + var rawline = reader.ReadLine(); + + if (string.IsNullOrEmpty(rawline)) + continue; + + var row = rawline.Split(new[] { ';' }); + + string? userId = null, userEmail = null, userCountry = null, userCustomAttributeName = null, userCustomAttributeValue = null; + if (row[0] != "##null##") + { + userId = row[0]; + userEmail = row[1] is "" or "##null##" ? null : row[1]; + userCountry = row[2] is "" or "##null##" ? null : row[2]; + if (row[3] is not ("" or "##null##")) + { + userCustomAttributeName = columns[3]; + userCustomAttributeValue = row[3]; + } + } + + for (var i = 4; i < columns.Length; i++) + { + yield return new[] + { + DescriptorInstance.SampleJsonFileName, columns[i], row[i], + userId, userEmail, userCountry, userCustomAttributeName, userCustomAttributeValue + }; + } + } + } + + protected virtual bool AssertValue(string expected, Func parse, T actual, string keyName, string? userId) => true; + + internal bool RunTest(IRolloutEvaluator evaluator, LoggerWrapper logger, string settingKey, string expectedReturnValue, User? user = null) + { + if (settingKey.StartsWith("bool", StringComparison.OrdinalIgnoreCase)) + { + var actual = evaluator.Evaluate(this.config, settingKey, false, user, null, logger).Value; + + return AssertValue(expectedReturnValue, static e => bool.Parse(e), actual, settingKey, user?.Identifier); + } + else if (settingKey.StartsWith("double", StringComparison.OrdinalIgnoreCase)) + { + var actual = evaluator.Evaluate(this.config, settingKey, double.NaN, user, null, logger).Value; + + return AssertValue(expectedReturnValue, static e => double.Parse(e, CultureInfo.InvariantCulture), actual, settingKey, user?.Identifier); + } + else if (settingKey.StartsWith("integer", StringComparison.OrdinalIgnoreCase)) + { + var actual = evaluator.Evaluate(this.config, settingKey, int.MinValue, user, null, logger).Value; + + return AssertValue(expectedReturnValue, static e => int.Parse(e, CultureInfo.InvariantCulture), actual, settingKey, user?.Identifier); + } + else if (settingKey.StartsWith("string", StringComparison.OrdinalIgnoreCase)) + { + var actual = evaluator.Evaluate(this.config, settingKey, string.Empty, user, null, logger).Value; + + return AssertValue(expectedReturnValue, static e => e, actual, settingKey, user?.Identifier); + } + else + { + var actual = evaluator.Evaluate(this.config, settingKey, (object?)null, user, null, logger).Value; + + return AssertValue(expectedReturnValue, static e => e, Convert.ToString(actual, CultureInfo.InvariantCulture), settingKey, user?.Identifier); + } + } + + internal bool RunTest(IRolloutEvaluator evaluator, LoggerWrapper logger, string settingKey, string expectedReturnValue, + string? userId, string? userEmail, string? userCountry, string? userCustomAttributeName, string? userCustomAttributeValue) + { + User? user = null; + if (userId is not null) + { + user = new User(userId) { Email = userEmail, Country = userCountry }; + if (userCustomAttributeValue is not null) + user.Custom[userCustomAttributeName!] = userCustomAttributeValue; + } + + return RunTest(evaluator, logger, settingKey, expectedReturnValue, user); + } + + internal int RunAllTests(IRolloutEvaluator evaluator, LoggerWrapper logger, object?[][] tests) + { + int i; + for (i = 0; i < tests.Length; i++) + { + var args = tests[i]; + + RunTest(evaluator, logger, (string)args[1]!, (string)args[2]!, + (string?)args[3], (string?)args[4], (string?)args[5], (string?)args[6], (string?)args[7]); + } + return i; + } +} diff --git a/src/ConfigCat.Client.Tests/strongname.snk b/src/ConfigCatClient.snk similarity index 100% rename from src/ConfigCat.Client.Tests/strongname.snk rename to src/ConfigCatClient.snk diff --git a/src/ConfigCatClient/ConfigCatClient.csproj b/src/ConfigCatClient/ConfigCatClient.csproj index 3bd947a3..92c695aa 100644 --- a/src/ConfigCatClient/ConfigCatClient.csproj +++ b/src/ConfigCatClient/ConfigCatClient.csproj @@ -5,7 +5,7 @@ ConfigCat.Client true false - strongname.snk + ..\ConfigCatClient.snk 0.1.0 Copyright © ConfigCat 2020 ConfigCat @@ -42,8 +42,6 @@ ConfigCat.Client.Benchmark - ConfigCat.Client.Benchmark - ConfigCat.Client.Benchmark true @@ -106,6 +104,7 @@ + diff --git a/src/ConfigCatClient/strongname.snk b/src/ConfigCatClient/strongname.snk deleted file mode 100644 index b6c29622f4faa690bf62767836051fa8d18717d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098o>p%3wB1%8=<$6sQgGOVHBb2Uhp+ zvT4#Vc>_m+#X~?6MkE`1y-n^OAY8Sh@L&ASXchpWSBqxwCukz`nS+U9bc7V=>^Hdb zxctO=b3hPAgNHv)oo4TH>`;ol)@T$a9&}Cg<6!}bl|AAx7At#ki@vY!f+SwYhU=3t zk*x-gTSMX68|q12HhWkpmDNrlH6!?-IbWhunWHO`d8G$xQesC5#X*K)tmg73X9>w&SC}grT=aM#aD?Eg7N0*|`OMoLI44HkL^H&GW{?@_4)b|~haqalna+zvTW`ssok$C`c{9l@BB9^P;HxXDraS zM`rIMW_KXd;;|Q5fm!6?xQAtYto`aTL-A=-&c@!QdF}#X3dy^n7mV;^Y;lMDaz<nGdJMsc#g%Zf@Q3@=DL*q~uigQPTIOiTJJQ_l^fjreIovl-GxSVxQU@gBk4b}X*f z(F$K$*N#u{cG}U=y{jZzDO9|)|5%Qu?U*wP_Yp$o?Bv{F^tO_&oQ{ZWe^m+Vq>DuX z=myPQpGzQt>8~Dw0o4_Du41x!ZxsFX#LXYI`k?KvNQ(|pFJ$T5&1@6bO02}+n+lr6 zAV&QPFnAZm>Ck<1d=S%8iT)26m>9n0%O!3Es^973y$LO@6l3kn_7V;d%Ubz)?&#ct i0Lm|?+Gu!4wSn3a=omchCR;I)K6jAtVnSZlIQ$yuq$nr=