diff --git a/test/Privileged.Components.Tests/Privileged.Components.Tests.csproj b/test/Privileged.Components.Tests/Privileged.Components.Tests.csproj index 859d427..b9a60db 100644 --- a/test/Privileged.Components.Tests/Privileged.Components.Tests.csproj +++ b/test/Privileged.Components.Tests/Privileged.Components.Tests.csproj @@ -15,6 +15,7 @@ + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test/Privileged.Tests/AuthorizationContextBenchmarks.cs b/test/Privileged.Tests/AuthorizationContextBenchmarks.cs new file mode 100644 index 0000000..fd80a16 --- /dev/null +++ b/test/Privileged.Tests/AuthorizationContextBenchmarks.cs @@ -0,0 +1,48 @@ +using BenchmarkDotNet.Attributes; + +using Bogus; + +namespace Privileged.Tests; + +[MemoryDiagnoser] +public class AuthorizationContextBenchmarks +{ + private List _rules; + private AuthorizationContext _authorziationContext; + + public AuthorizationContextBenchmarks() + { + var generator = new Faker("en_US") + .UseSeed(2024) + .CustomInstantiator((f) => + new AuthorizationRule + ( + Action: f.Random.WeightedRandom(["read", "update", "delete", "all"], [.40f, .30f, .20f, 10f]), + Subject: f.Name.FirstName(), + Fields: f.Random.WeightedRandom?>([null, ["id"]], [.90f, .10f]), + Denied: f.Random.WeightedRandom([false, true], [.90f, .10f]) + ) + ); + + _rules = generator.Generate(1000); + _authorziationContext = new AuthorizationContext(_rules); + } + + [Benchmark] + public bool AuthorizedReadBenchmark() + { + return _authorziationContext.Authorized("read", "Bob"); + } + + [Benchmark] + public bool AuthorizedAllBenchmark() + { + return _authorziationContext.Authorized("delete", "all"); + } + + [Benchmark] + public bool AuthorizedFieldBenchmark() + { + return _authorziationContext.Authorized("update", "Allen", "id"); + } +} diff --git a/test/Privileged.Tests/AuthorizationContextPerformanceTests.cs b/test/Privileged.Tests/AuthorizationContextPerformanceTests.cs new file mode 100644 index 0000000..ef72498 --- /dev/null +++ b/test/Privileged.Tests/AuthorizationContextPerformanceTests.cs @@ -0,0 +1,38 @@ +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Exporters; +using BenchmarkDotNet.Jobs; +using BenchmarkDotNet.Loggers; +using BenchmarkDotNet.Running; + +using Xunit.Abstractions; + +namespace Privileged.Tests; + +public class AuthorizationContextPerformanceTests +{ + private readonly ITestOutputHelper _output; + + public AuthorizationContextPerformanceTests(ITestOutputHelper output) + { + _output = output; + } + + [Fact] + public void BenchmarkRunnerTest() + { + var config = ManualConfig + .CreateMinimumViable() + .AddJob(Job.ShortRun) + .WithOptions(ConfigOptions.DisableOptimizationsValidator) + .WithOption(ConfigOptions.JoinSummary, true); + + var summary = BenchmarkRunner.Run(config); + + // write benchmark summary + var logger = new AccumulationLogger(); + + MarkdownExporter.Console.ExportToLog(summary, logger); + + _output.WriteLine(logger.GetLog()); + } +} diff --git a/test/Privileged.Tests/AuthorizationContextTests.cs b/test/Privileged.Tests/AuthorizationContextTests.cs index 9a1a50f..08956b7 100644 --- a/test/Privileged.Tests/AuthorizationContextTests.cs +++ b/test/Privileged.Tests/AuthorizationContextTests.cs @@ -1,3 +1,5 @@ +using System.Text.Json; + namespace Privileged.Tests; public class AuthorizationContextTests @@ -11,16 +13,16 @@ public void AllowByDefault() .Forbid("publish", "Post") .Build(); - Assert.True(context.Authorized("read", "Post")); - Assert.True(context.Authorized("update", "Post")); - Assert.True(context.Authorized("archive", "Post")); - Assert.False(context.Authorized(null, "Post")); - Assert.False(context.Authorized("archive", null)); - Assert.False(context.Authorized("read", "User")); - Assert.True(context.Authorized("delete", "Post")); - Assert.False(context.Authorized("publish", "Post")); - Assert.True(context.Authorized("test", "User")); - Assert.True(context.Authorized("test", "Post")); + context.Authorized("read", "Post").Should().BeTrue(); + context.Authorized("update", "Post").Should().BeTrue(); + context.Authorized("archive", "Post").Should().BeTrue(); + context.Authorized(null, "Post").Should().BeFalse(); + context.Authorized("archive", null).Should().BeFalse(); + context.Authorized("read", "User").Should().BeFalse(); + context.Authorized("delete", "Post").Should().BeTrue(); + context.Authorized("publish", "Post").Should().BeFalse(); + context.Authorized("test", "User").Should().BeTrue(); + context.Authorized("test", "Post").Should().BeTrue(); } [Fact] @@ -31,9 +33,9 @@ public void AllowConstructRules() .Allow("update", "Article") .Build(); - Assert.True(context.Authorized("read", "Article")); - Assert.True(context.Authorized("update", "Article")); - Assert.False(context.Authorized("delete", "Article")); + context.Authorized("read", "Article").Should().BeTrue(); + context.Authorized("update", "Article").Should().BeTrue(); + context.Authorized("delete", "Article").Should().BeFalse(); } [Fact] @@ -43,9 +45,9 @@ public void AllowSpecifyMultipleActions() .Allow(["read", "update"], "Post") .Build(); - Assert.True(context.Authorized("read", "Post")); - Assert.True(context.Authorized("update", "Post")); - Assert.False(context.Authorized("delete", "Post")); + context.Authorized("read", "Post").Should().BeTrue(); + context.Authorized("update", "Post").Should().BeTrue(); + context.Authorized("delete", "Post").Should().BeFalse(); } [Fact] @@ -55,9 +57,9 @@ public void AllowSpecifyMultipleSubjects() .Allow("read", ["Post", "User"]) .Build(); - Assert.True(context.Authorized("read", "Post")); - Assert.True(context.Authorized("read", "User")); - Assert.False(context.Authorized("read", "Article")); + context.Authorized("read", "Post").Should().BeTrue(); + context.Authorized("read", "User").Should().BeTrue(); + context.Authorized("read", "Article").Should().BeFalse(); } [Fact] @@ -68,12 +70,12 @@ public void AllowRulesWithFields() .Allow("read", "User") .Build(); - Assert.True(context.Authorized("read", "Post")); - Assert.True(context.Authorized("read", "Post", "id")); - Assert.True(context.Authorized("read", "Post", "title")); - Assert.False(context.Authorized("read", "Post", "ssn")); + context.Authorized("read", "Post").Should().BeTrue(); + context.Authorized("read", "Post", "id").Should().BeTrue(); + context.Authorized("read", "Post", "title").Should().BeTrue(); + context.Authorized("read", "Post", "ssn").Should().BeFalse(); - Assert.True(context.Authorized("read", "User")); - Assert.True(context.Authorized("read", "User", "id")); + context.Authorized("read", "User").Should().BeTrue(); + context.Authorized("read", "User", "id").Should().BeTrue(); } } diff --git a/test/Privileged.Tests/GlobalUsings.cs b/test/Privileged.Tests/GlobalUsings.cs index 8c927eb..7b25ddd 100644 --- a/test/Privileged.Tests/GlobalUsings.cs +++ b/test/Privileged.Tests/GlobalUsings.cs @@ -1 +1,2 @@ -global using Xunit; \ No newline at end of file +global using FluentAssertions; +global using Xunit; diff --git a/test/Privileged.Tests/JsonSerializationTests.cs b/test/Privileged.Tests/JsonSerializationTests.cs new file mode 100644 index 0000000..32ff41b --- /dev/null +++ b/test/Privileged.Tests/JsonSerializationTests.cs @@ -0,0 +1,55 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +using Xunit.Abstractions; + +namespace Privileged.Tests; + +public class JsonSerializationTests +{ + private readonly ITestOutputHelper _output; + + public JsonSerializationTests(ITestOutputHelper output) + { + _output = output; + } + + [Fact] + public void SerializationRules() + { + var context = new AuthorizationBuilder() + .Allow("test", AuthorizationSubjects.All) + .Allow(AuthorizationActions.All, "Post") + .Allow("read", "User", ["title", "id"]) + .Forbid("publish", "Post") + .Build(); + + var options = new JsonSerializerOptions(JsonSerializerDefaults.Web) + { + WriteIndented = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + TypeInfoResolver = AuthorizationJsonContext.Default + }; + + var json = JsonSerializer.Serialize(context.Rules, options); + json.Should().NotBeNullOrEmpty(); + + _output.WriteLine(json); + + var rules = JsonSerializer.Deserialize>(json, options); + rules.Should().NotBeNullOrEmpty(); + rules.Count.Should().Be(4); + + var jsonContext = new AuthorizationContext(rules); + jsonContext.Should().NotBeNull(); + + var contextJson = JsonSerializer.Serialize(jsonContext, options); + contextJson.Should().NotBeNullOrEmpty(); + } +} + +[JsonSerializable(typeof(AuthorizationContext))] +[JsonSerializable(typeof(AuthorizationRule))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(IReadOnlyCollection))] +public partial class AuthorizationJsonContext : JsonSerializerContext; diff --git a/test/Privileged.Tests/Privileged.Tests.csproj b/test/Privileged.Tests/Privileged.Tests.csproj index f8b2350..ece150c 100644 --- a/test/Privileged.Tests/Privileged.Tests.csproj +++ b/test/Privileged.Tests/Privileged.Tests.csproj @@ -1,7 +1,7 @@ - net6.0;net8.0 + net8.0 enable enable latest @@ -11,6 +11,9 @@ + + + all