Fix build and code structure improvements. New but essential UI functionality. CI improvements. Documentation improvements. AI module improvements.
This commit is contained in:
@@ -1,111 +1,215 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.Notifier", "StellaOps.Notifier", "{B561C84F-7AB2-7B4E-D703-D6D5908493D1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Notifier.Tests", "StellaOps.Notifier\StellaOps.Notifier.Tests\StellaOps.Notifier.Tests.csproj", "{65E29FD4-99F5-49DA-BBCC-BE04096F9E54}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Notifier.Worker", "StellaOps.Notifier\StellaOps.Notifier.Worker\StellaOps.Notifier.Worker.csproj", "{1488AD55-0086-46D2-967B-8D0E07161876}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Notify.Models", "..\Notify\__Libraries\StellaOps.Notify.Models\StellaOps.Notify.Models.csproj", "{52391B39-F69D-4C9A-9588-EAC5AD023546}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Notify.Queue", "..\Notify\__Libraries\StellaOps.Notify.Queue\StellaOps.Notify.Queue.csproj", "{6D2D2F1F-45AA-4F52-AD1B-1F7562F7C714}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Notify.Engine", "..\Notify\__Libraries\StellaOps.Notify.Engine\StellaOps.Notify.Engine.csproj", "{E61AA8CA-29C2-4BEB-B53B-36B7DE31E9AE}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Notifier.WebService", "StellaOps.Notifier\StellaOps.Notifier.WebService\StellaOps.Notifier.WebService.csproj", "{F6252853-A408-4658-9006-5DDF140A536A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{65E29FD4-99F5-49DA-BBCC-BE04096F9E54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{65E29FD4-99F5-49DA-BBCC-BE04096F9E54}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{65E29FD4-99F5-49DA-BBCC-BE04096F9E54}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{65E29FD4-99F5-49DA-BBCC-BE04096F9E54}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{65E29FD4-99F5-49DA-BBCC-BE04096F9E54}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{65E29FD4-99F5-49DA-BBCC-BE04096F9E54}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{65E29FD4-99F5-49DA-BBCC-BE04096F9E54}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{65E29FD4-99F5-49DA-BBCC-BE04096F9E54}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{65E29FD4-99F5-49DA-BBCC-BE04096F9E54}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{65E29FD4-99F5-49DA-BBCC-BE04096F9E54}.Release|x64.Build.0 = Release|Any CPU
|
||||
{65E29FD4-99F5-49DA-BBCC-BE04096F9E54}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{65E29FD4-99F5-49DA-BBCC-BE04096F9E54}.Release|x86.Build.0 = Release|Any CPU
|
||||
{1488AD55-0086-46D2-967B-8D0E07161876}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1488AD55-0086-46D2-967B-8D0E07161876}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1488AD55-0086-46D2-967B-8D0E07161876}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{1488AD55-0086-46D2-967B-8D0E07161876}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{1488AD55-0086-46D2-967B-8D0E07161876}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{1488AD55-0086-46D2-967B-8D0E07161876}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{1488AD55-0086-46D2-967B-8D0E07161876}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1488AD55-0086-46D2-967B-8D0E07161876}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1488AD55-0086-46D2-967B-8D0E07161876}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{1488AD55-0086-46D2-967B-8D0E07161876}.Release|x64.Build.0 = Release|Any CPU
|
||||
{1488AD55-0086-46D2-967B-8D0E07161876}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{1488AD55-0086-46D2-967B-8D0E07161876}.Release|x86.Build.0 = Release|Any CPU
|
||||
{52391B39-F69D-4C9A-9588-EAC5AD023546}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{52391B39-F69D-4C9A-9588-EAC5AD023546}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{52391B39-F69D-4C9A-9588-EAC5AD023546}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{52391B39-F69D-4C9A-9588-EAC5AD023546}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{52391B39-F69D-4C9A-9588-EAC5AD023546}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{52391B39-F69D-4C9A-9588-EAC5AD023546}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{52391B39-F69D-4C9A-9588-EAC5AD023546}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{52391B39-F69D-4C9A-9588-EAC5AD023546}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{52391B39-F69D-4C9A-9588-EAC5AD023546}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{52391B39-F69D-4C9A-9588-EAC5AD023546}.Release|x64.Build.0 = Release|Any CPU
|
||||
{52391B39-F69D-4C9A-9588-EAC5AD023546}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{52391B39-F69D-4C9A-9588-EAC5AD023546}.Release|x86.Build.0 = Release|Any CPU
|
||||
{6D2D2F1F-45AA-4F52-AD1B-1F7562F7C714}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6D2D2F1F-45AA-4F52-AD1B-1F7562F7C714}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6D2D2F1F-45AA-4F52-AD1B-1F7562F7C714}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{6D2D2F1F-45AA-4F52-AD1B-1F7562F7C714}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{6D2D2F1F-45AA-4F52-AD1B-1F7562F7C714}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{6D2D2F1F-45AA-4F52-AD1B-1F7562F7C714}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{6D2D2F1F-45AA-4F52-AD1B-1F7562F7C714}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6D2D2F1F-45AA-4F52-AD1B-1F7562F7C714}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6D2D2F1F-45AA-4F52-AD1B-1F7562F7C714}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{6D2D2F1F-45AA-4F52-AD1B-1F7562F7C714}.Release|x64.Build.0 = Release|Any CPU
|
||||
{6D2D2F1F-45AA-4F52-AD1B-1F7562F7C714}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{6D2D2F1F-45AA-4F52-AD1B-1F7562F7C714}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E61AA8CA-29C2-4BEB-B53B-36B7DE31E9AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E61AA8CA-29C2-4BEB-B53B-36B7DE31E9AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E61AA8CA-29C2-4BEB-B53B-36B7DE31E9AE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E61AA8CA-29C2-4BEB-B53B-36B7DE31E9AE}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E61AA8CA-29C2-4BEB-B53B-36B7DE31E9AE}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E61AA8CA-29C2-4BEB-B53B-36B7DE31E9AE}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E61AA8CA-29C2-4BEB-B53B-36B7DE31E9AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E61AA8CA-29C2-4BEB-B53B-36B7DE31E9AE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E61AA8CA-29C2-4BEB-B53B-36B7DE31E9AE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E61AA8CA-29C2-4BEB-B53B-36B7DE31E9AE}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E61AA8CA-29C2-4BEB-B53B-36B7DE31E9AE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E61AA8CA-29C2-4BEB-B53B-36B7DE31E9AE}.Release|x86.Build.0 = Release|Any CPU
|
||||
{F6252853-A408-4658-9006-5DDF140A536A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F6252853-A408-4658-9006-5DDF140A536A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F6252853-A408-4658-9006-5DDF140A536A}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{F6252853-A408-4658-9006-5DDF140A536A}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{F6252853-A408-4658-9006-5DDF140A536A}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F6252853-A408-4658-9006-5DDF140A536A}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{F6252853-A408-4658-9006-5DDF140A536A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F6252853-A408-4658-9006-5DDF140A536A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F6252853-A408-4658-9006-5DDF140A536A}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{F6252853-A408-4658-9006-5DDF140A536A}.Release|x64.Build.0 = Release|Any CPU
|
||||
{F6252853-A408-4658-9006-5DDF140A536A}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F6252853-A408-4658-9006-5DDF140A536A}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{65E29FD4-99F5-49DA-BBCC-BE04096F9E54} = {B561C84F-7AB2-7B4E-D703-D6D5908493D1}
|
||||
{1488AD55-0086-46D2-967B-8D0E07161876} = {B561C84F-7AB2-7B4E-D703-D6D5908493D1}
|
||||
{F6252853-A408-4658-9006-5DDF140A536A} = {B561C84F-7AB2-7B4E-D703-D6D5908493D1}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.Notifier", "StellaOps.Notifier", "{639596D3-53A6-3894-2109-085AA8166F49}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.Notifier.Tests", "StellaOps.Notifier.Tests", "{37856662-AA7B-BD21-3B47-3480699EA4E8}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.Notifier.WebService", "StellaOps.Notifier.WebService", "{977AC9AB-7D67-08D4-2B1C-DBE2ACC89C97}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.Notifier.Worker", "StellaOps.Notifier.Worker", "{E19B124B-8FBE-341C-D798-9B6263896CBD}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "__External", "__External", "{5B52EF8A-3661-DCFF-797D-BC4D6AC60BDA}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AirGap", "AirGap", "{F310596E-88BB-9E54-885E-21C61971917E}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.AirGap.Policy", "StellaOps.AirGap.Policy", "{D9492ED1-A812-924B-65E4-F518592B49BB}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.AirGap.Policy", "StellaOps.AirGap.Policy", "{3823DE1E-2ACE-C956-99E1-00DB786D9E1D}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Notify", "Notify", "{D2162FEA-AFA4-2A88-6444-2F6D845260BB}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "__Libraries", "__Libraries", "{63EAEA3B-ADC9-631D-774E-7AA04490EDDD}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.Notify.Engine", "StellaOps.Notify.Engine", "{FFBCC722-2884-8426-A5ED-D73D8A0C5CE6}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.Notify.Models", "StellaOps.Notify.Models", "{B0F64757-F7A7-1A11-8DEC-BAC72EB5EC29}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.Notify.Persistence", "StellaOps.Notify.Persistence", "{C5F86BAD-155A-591C-9610-55D40F59C775}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.Notify.Queue", "StellaOps.Notify.Queue", "{4F9F3B3A-221C-4F00-B4E9-4AA44C0C8F9A}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Router", "Router", "{FC018E5B-1E2F-DE19-1E97-0C845058C469}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "__Libraries", "__Libraries", "{1BE5B76C-B486-560B-6CB2-44C6537249AA}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.Microservice", "StellaOps.Microservice", "{3DE1DCDC-C845-4AC7-7B66-34B0A9E8626B}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.Microservice.AspNetCore", "StellaOps.Microservice.AspNetCore", "{6FA01E92-606B-0CB8-8583-6F693A903CFC}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.Router.AspNet", "StellaOps.Router.AspNet", "{A5994E92-7E0E-89FE-5628-DE1A0176B8BA}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.Router.Common", "StellaOps.Router.Common", "{54C11B29-4C54-7255-AB44-BEB63AF9BD1F}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "__Libraries", "__Libraries", "{1345DD29-BB3A-FB5F-4B3D-E29F6045A27A}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.Canonical.Json", "StellaOps.Canonical.Json", "{79E122F4-2325-3E92-438E-5825A307B594}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.Cryptography", "StellaOps.Cryptography", "{66557252-B5C4-664B-D807-07018C627474}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.Infrastructure.EfCore", "StellaOps.Infrastructure.EfCore", "{FCD529E0-DD17-6587-B29C-12D425C0AD0C}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.Infrastructure.Postgres", "StellaOps.Infrastructure.Postgres", "{61B23570-4F2D-B060-BE1F-37995682E494}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StellaOps.TestKit", "StellaOps.TestKit", "{8380A20C-A5B8-EE91-1A58-270323688CB9}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.AirGap.Policy", "E:\dev\git.stella-ops.org\src\AirGap\StellaOps.AirGap.Policy\StellaOps.AirGap.Policy\StellaOps.AirGap.Policy.csproj", "{AD31623A-BC43-52C2-D906-AC1D8784A541}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Canonical.Json", "E:\dev\git.stella-ops.org\src\__Libraries\StellaOps.Canonical.Json\StellaOps.Canonical.Json.csproj", "{AF9E7F02-25AD-3540-18D7-F6A4F8BA5A60}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Cryptography", "E:\dev\git.stella-ops.org\src\__Libraries\StellaOps.Cryptography\StellaOps.Cryptography.csproj", "{F664A948-E352-5808-E780-77A03F19E93E}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Infrastructure.EfCore", "E:\dev\git.stella-ops.org\src\__Libraries\StellaOps.Infrastructure.EfCore\StellaOps.Infrastructure.EfCore.csproj", "{A63897D9-9531-989B-7309-E384BCFC2BB9}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Infrastructure.Postgres", "E:\dev\git.stella-ops.org\src\__Libraries\StellaOps.Infrastructure.Postgres\StellaOps.Infrastructure.Postgres.csproj", "{8C594D82-3463-3367-4F06-900AC707753D}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Microservice", "E:\dev\git.stella-ops.org\src\Router\__Libraries\StellaOps.Microservice\StellaOps.Microservice.csproj", "{BAD08D96-A80A-D27F-5D9C-656AEEB3D568}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Microservice.AspNetCore", "E:\dev\git.stella-ops.org\src\Router\__Libraries\StellaOps.Microservice.AspNetCore\StellaOps.Microservice.AspNetCore.csproj", "{F63694F1-B56D-6E72-3F5D-5D38B1541F0F}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Notifier.Tests", "StellaOps.Notifier\StellaOps.Notifier.Tests\StellaOps.Notifier.Tests.csproj", "{8188439A-89F5-3400-98E8-9A1E10FDC6E9}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Notifier.WebService", "StellaOps.Notifier\StellaOps.Notifier.WebService\StellaOps.Notifier.WebService.csproj", "{D4AF8947-BA45-BD10-DA38-18C1EB291161}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Notifier.Worker", "StellaOps.Notifier\StellaOps.Notifier.Worker\StellaOps.Notifier.Worker.csproj", "{DADF4D7D-CF18-3174-6EFB-53281F0F02E4}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Notify.Engine", "E:\dev\git.stella-ops.org\src\Notify\__Libraries\StellaOps.Notify.Engine\StellaOps.Notify.Engine.csproj", "{8ED04856-EACE-5385-CDFB-BBA78C545AA7}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Notify.Models", "E:\dev\git.stella-ops.org\src\Notify\__Libraries\StellaOps.Notify.Models\StellaOps.Notify.Models.csproj", "{20D1569C-2A47-38B8-075E-47225B674394}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Notify.Persistence", "E:\dev\git.stella-ops.org\src\Notify\__Libraries\StellaOps.Notify.Persistence\StellaOps.Notify.Persistence.csproj", "{2F7AA715-25AE-086A-7DF4-CAB5EF00E2B7}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Notify.Queue", "E:\dev\git.stella-ops.org\src\Notify\__Libraries\StellaOps.Notify.Queue\StellaOps.Notify.Queue.csproj", "{6A93F807-4839-1633-8B24-810660BB4C28}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Router.AspNet", "E:\dev\git.stella-ops.org\src\Router\__Libraries\StellaOps.Router.AspNet\StellaOps.Router.AspNet.csproj", "{79104479-B087-E5D0-5523-F1803282A246}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Router.Common", "E:\dev\git.stella-ops.org\src\Router\__Libraries\StellaOps.Router.Common\StellaOps.Router.Common.csproj", "{F17A6F0B-3120-2BA9-84D8-5F8BA0B9705D}"
|
||||
|
||||
EndProject
|
||||
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.TestKit", "E:\dev\git.stella-ops.org\src\__Libraries\StellaOps.TestKit\StellaOps.TestKit.csproj", "{AF043113-CCE3-59C1-DF71-9804155F26A8}"
|
||||
|
||||
EndProject
|
||||
|
||||
Global
|
||||
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
||||
Release|Any CPU = Release|Any CPU
|
||||
|
||||
EndGlobalSection
|
||||
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
|
||||
{AD31623A-BC43-52C2-D906-AC1D8784A541}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
|
||||
{AD31623A-BC43-52C2-D906-AC1D8784A541}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
|
||||
{AD31623A-BC43-52C2-D906-AC1D8784A541}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
||||
{AD31623A-BC43-52C2-D906-AC1D8784A541}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
|
||||
{AF9E7F02-25AD-3540-18D7-F6A4F8BA5A60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
|
||||
{AF9E7F02-25AD-3540-18D7-F6A4F8BA5A60}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
|
||||
{AF9E7F02-25AD-3540-18D7-F6A4F8BA5A60}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
||||
{AF9E7F02-25AD-3540-18D7-F6A4F8BA5A60}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
|
||||
{F664A948-E352-5808-E780-77A03F19E93E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
|
||||
{F664A948-E352-5808-E780-77A03F19E93E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
|
||||
{F664A948-E352-5808-E780-77A03F19E93E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
||||
{F664A948-E352-5808-E780-77A03F19E93E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
|
||||
{A63897D9-9531-989B-7309-E384BCFC2BB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ public sealed class AttestationEventEndpointTests : IClassFixture<NotifierApplic
|
||||
};
|
||||
message.Headers.Add("X-StellaOps-Tenant", "tenant-sample");
|
||||
|
||||
var response = await client.SendAsync(message, TestContext.Current.CancellationToken);
|
||||
var response = await client.SendAsync(message, CancellationToken.None);
|
||||
|
||||
Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);
|
||||
Assert.Single(recordingQueue.Published);
|
||||
|
||||
@@ -24,23 +24,23 @@ public sealed class AttestationTemplateSeederTests
|
||||
templateRepo,
|
||||
contentRoot,
|
||||
logger,
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
|
||||
var seededRouting = await AttestationTemplateSeeder.SeedRoutingAsync(
|
||||
channelRepo,
|
||||
ruleRepo,
|
||||
contentRoot,
|
||||
logger,
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
|
||||
Assert.True(seededTemplates >= 6, "Expected attestation templates to be seeded.");
|
||||
Assert.True(seededRouting >= 0, $"Expected attestation routing seed to create channels and rules but got {seededRouting}.");
|
||||
|
||||
var templates = await templateRepo.ListAsync("bootstrap", TestContext.Current.CancellationToken);
|
||||
var templates = await templateRepo.ListAsync("bootstrap", CancellationToken.None);
|
||||
Assert.Contains(templates, t => t.Key == "tmpl-attest-key-rotation");
|
||||
Assert.Contains(templates, t => t.Key == "tmpl-attest-transparency-anomaly");
|
||||
|
||||
var rules = await ruleRepo.ListAsync("bootstrap", TestContext.Current.CancellationToken);
|
||||
var rules = await ruleRepo.ListAsync("bootstrap", CancellationToken.None);
|
||||
Assert.Contains(rules, r => r.Match.EventKinds.Contains("authority.keys.rotated"));
|
||||
Assert.Contains(rules, r => r.Match.EventKinds.Contains("attestor.transparency.anomaly"));
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ public class CorrelationEngineTests
|
||||
.ReturnsAsync(ThrottleCheckResult.NotThrottled());
|
||||
|
||||
// Act
|
||||
var result = await _engine.CorrelateAsync(notifyEvent);
|
||||
var result = await _engine.CorrelateAsync(notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Correlated);
|
||||
@@ -110,7 +110,7 @@ public class CorrelationEngineTests
|
||||
.ReturnsAsync(ThrottleCheckResult.NotThrottled());
|
||||
|
||||
// Act
|
||||
var result = await _engine.CorrelateAsync(notifyEvent);
|
||||
var result = await _engine.CorrelateAsync(notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsNewIncident);
|
||||
@@ -145,7 +145,7 @@ public class CorrelationEngineTests
|
||||
.ReturnsAsync(ThrottleCheckResult.NotThrottled());
|
||||
|
||||
// Act
|
||||
var result = await _engine.CorrelateAsync(notifyEvent);
|
||||
var result = await _engine.CorrelateAsync(notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsNewIncident);
|
||||
@@ -174,7 +174,7 @@ public class CorrelationEngineTests
|
||||
.ReturnsAsync(SuppressionCheckResult.Suppressed("Quiet hours", "quiet_hours"));
|
||||
|
||||
// Act
|
||||
var result = await _engine.CorrelateAsync(notifyEvent);
|
||||
var result = await _engine.CorrelateAsync(notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.ShouldNotify);
|
||||
@@ -208,7 +208,7 @@ public class CorrelationEngineTests
|
||||
.ReturnsAsync(ThrottleCheckResult.Throttled(15));
|
||||
|
||||
// Act
|
||||
var result = await _engine.CorrelateAsync(notifyEvent);
|
||||
var result = await _engine.CorrelateAsync(notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.ShouldNotify);
|
||||
@@ -249,7 +249,7 @@ public class CorrelationEngineTests
|
||||
.ReturnsAsync(ThrottleCheckResult.NotThrottled());
|
||||
|
||||
// Act
|
||||
await _engine.CorrelateAsync(notifyEvent);
|
||||
await _engine.CorrelateAsync(notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
_keyBuilderFactory.Verify(f => f.GetBuilder("template"), Times.Once);
|
||||
@@ -289,7 +289,7 @@ public class CorrelationEngineTests
|
||||
.ReturnsAsync(ThrottleCheckResult.NotThrottled());
|
||||
|
||||
// Act
|
||||
await _engine.CorrelateAsync(notifyEvent);
|
||||
await _engine.CorrelateAsync(notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
_keyBuilderFactory.Verify(f => f.GetBuilder("custom"), Times.Once);
|
||||
@@ -323,7 +323,7 @@ public class CorrelationEngineTests
|
||||
.ReturnsAsync(ThrottleCheckResult.NotThrottled());
|
||||
|
||||
// Act
|
||||
var result = await _engine.CorrelateAsync(notifyEvent);
|
||||
var result = await _engine.CorrelateAsync(notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.ShouldNotify);
|
||||
@@ -358,7 +358,7 @@ public class CorrelationEngineTests
|
||||
.ReturnsAsync(ThrottleCheckResult.NotThrottled());
|
||||
|
||||
// Act
|
||||
var result = await _engine.CorrelateAsync(notifyEvent);
|
||||
var result = await _engine.CorrelateAsync(notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.ShouldNotify);
|
||||
@@ -393,7 +393,7 @@ public class CorrelationEngineTests
|
||||
.ReturnsAsync(ThrottleCheckResult.NotThrottled());
|
||||
|
||||
// Act
|
||||
var result = await _engine.CorrelateAsync(notifyEvent);
|
||||
var result = await _engine.CorrelateAsync(notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.ShouldNotify);
|
||||
@@ -406,7 +406,7 @@ public class CorrelationEngineTests
|
||||
_options.ThrottlingEnabled = false;
|
||||
|
||||
// Act
|
||||
var result = await _engine.CheckThrottleAsync("tenant1", "key1", null);
|
||||
var result = await _engine.CheckThrottleAsync("tenant1", "key1", null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsThrottled);
|
||||
|
||||
@@ -29,8 +29,7 @@ public class InMemoryIncidentManagerTests
|
||||
public async Task GetOrCreateIncidentAsync_CreatesNewIncident()
|
||||
{
|
||||
// Act
|
||||
var incident = await _manager.GetOrCreateIncidentAsync(
|
||||
"tenant1", "correlation-key", "security.alert", "Test Alert");
|
||||
var incident = await _manager.GetOrCreateIncidentAsync("tenant1", "correlation-key", "security.alert", "Test Alert", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(incident);
|
||||
@@ -47,13 +46,11 @@ public class InMemoryIncidentManagerTests
|
||||
public async Task GetOrCreateIncidentAsync_ReturnsSameIncidentWithinWindow()
|
||||
{
|
||||
// Arrange
|
||||
var incident1 = await _manager.GetOrCreateIncidentAsync(
|
||||
"tenant1", "correlation-key", "security.alert", "Test Alert");
|
||||
var incident1 = await _manager.GetOrCreateIncidentAsync("tenant1", "correlation-key", "security.alert", "Test Alert", CancellationToken.None);
|
||||
|
||||
// Act - request again within correlation window
|
||||
_timeProvider.Advance(TimeSpan.FromMinutes(30));
|
||||
var incident2 = await _manager.GetOrCreateIncidentAsync(
|
||||
"tenant1", "correlation-key", "security.alert", "Test Alert");
|
||||
var incident2 = await _manager.GetOrCreateIncidentAsync("tenant1", "correlation-key", "security.alert", "Test Alert", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(incident1.IncidentId, incident2.IncidentId);
|
||||
@@ -63,16 +60,14 @@ public class InMemoryIncidentManagerTests
|
||||
public async Task GetOrCreateIncidentAsync_CreatesNewIncidentOutsideWindow()
|
||||
{
|
||||
// Arrange
|
||||
var incident1 = await _manager.GetOrCreateIncidentAsync(
|
||||
"tenant1", "correlation-key", "security.alert", "Test Alert");
|
||||
var incident1 = await _manager.GetOrCreateIncidentAsync("tenant1", "correlation-key", "security.alert", "Test Alert", CancellationToken.None);
|
||||
|
||||
// Record an event to set LastOccurrence
|
||||
await _manager.RecordEventAsync("tenant1", incident1.IncidentId, "event-1");
|
||||
await _manager.RecordEventAsync("tenant1", incident1.IncidentId, "event-1", CancellationToken.None);
|
||||
|
||||
// Act - request again outside correlation window
|
||||
_timeProvider.Advance(TimeSpan.FromHours(2));
|
||||
var incident2 = await _manager.GetOrCreateIncidentAsync(
|
||||
"tenant1", "correlation-key", "security.alert", "Test Alert");
|
||||
var incident2 = await _manager.GetOrCreateIncidentAsync("tenant1", "correlation-key", "security.alert", "Test Alert", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotEqual(incident1.IncidentId, incident2.IncidentId);
|
||||
@@ -82,14 +77,12 @@ public class InMemoryIncidentManagerTests
|
||||
public async Task GetOrCreateIncidentAsync_CreatesNewIncidentAfterResolution()
|
||||
{
|
||||
// Arrange
|
||||
var incident1 = await _manager.GetOrCreateIncidentAsync(
|
||||
"tenant1", "correlation-key", "security.alert", "Test Alert");
|
||||
var incident1 = await _manager.GetOrCreateIncidentAsync("tenant1", "correlation-key", "security.alert", "Test Alert", CancellationToken.None);
|
||||
|
||||
await _manager.ResolveAsync("tenant1", incident1.IncidentId, "operator");
|
||||
await _manager.ResolveAsync("tenant1", incident1.IncidentId, "operator", cancellationToken: CancellationToken.None);
|
||||
|
||||
// Act - request again after resolution
|
||||
var incident2 = await _manager.GetOrCreateIncidentAsync(
|
||||
"tenant1", "correlation-key", "security.alert", "Test Alert");
|
||||
var incident2 = await _manager.GetOrCreateIncidentAsync("tenant1", "correlation-key", "security.alert", "Test Alert", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotEqual(incident1.IncidentId, incident2.IncidentId);
|
||||
@@ -99,11 +92,10 @@ public class InMemoryIncidentManagerTests
|
||||
public async Task RecordEventAsync_IncrementsEventCount()
|
||||
{
|
||||
// Arrange
|
||||
var incident = await _manager.GetOrCreateIncidentAsync(
|
||||
"tenant1", "correlation-key", "security.alert", "Test Alert");
|
||||
var incident = await _manager.GetOrCreateIncidentAsync("tenant1", "correlation-key", "security.alert", "Test Alert", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var updated = await _manager.RecordEventAsync("tenant1", incident.IncidentId, "event-1");
|
||||
var updated = await _manager.RecordEventAsync("tenant1", incident.IncidentId, "event-1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, updated.EventCount);
|
||||
@@ -114,14 +106,13 @@ public class InMemoryIncidentManagerTests
|
||||
public async Task RecordEventAsync_UpdatesLastOccurrence()
|
||||
{
|
||||
// Arrange
|
||||
var incident = await _manager.GetOrCreateIncidentAsync(
|
||||
"tenant1", "correlation-key", "security.alert", "Test Alert");
|
||||
var incident = await _manager.GetOrCreateIncidentAsync("tenant1", "correlation-key", "security.alert", "Test Alert", CancellationToken.None);
|
||||
|
||||
var initialTime = incident.LastOccurrence;
|
||||
|
||||
// Act
|
||||
_timeProvider.Advance(TimeSpan.FromMinutes(10));
|
||||
var updated = await _manager.RecordEventAsync("tenant1", incident.IncidentId, "event-1");
|
||||
var updated = await _manager.RecordEventAsync("tenant1", incident.IncidentId, "event-1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(updated.LastOccurrence > initialTime);
|
||||
@@ -132,13 +123,12 @@ public class InMemoryIncidentManagerTests
|
||||
{
|
||||
// Arrange
|
||||
_options.ReopenOnNewEvent = true;
|
||||
var incident = await _manager.GetOrCreateIncidentAsync(
|
||||
"tenant1", "correlation-key", "security.alert", "Test Alert");
|
||||
var incident = await _manager.GetOrCreateIncidentAsync("tenant1", "correlation-key", "security.alert", "Test Alert", CancellationToken.None);
|
||||
|
||||
await _manager.AcknowledgeAsync("tenant1", incident.IncidentId, "operator");
|
||||
await _manager.AcknowledgeAsync("tenant1", incident.IncidentId, "operator", cancellationToken: CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var updated = await _manager.RecordEventAsync("tenant1", incident.IncidentId, "event-1");
|
||||
var updated = await _manager.RecordEventAsync("tenant1", incident.IncidentId, "event-1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(IncidentStatus.Open, updated.Status);
|
||||
@@ -149,19 +139,17 @@ public class InMemoryIncidentManagerTests
|
||||
{
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => _manager.RecordEventAsync("tenant1", "unknown-id", "event-1"));
|
||||
() => _manager.RecordEventAsync("tenant1", "unknown-id", "event-1", CancellationToken.None));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AcknowledgeAsync_SetsAcknowledgedStatus()
|
||||
{
|
||||
// Arrange
|
||||
var incident = await _manager.GetOrCreateIncidentAsync(
|
||||
"tenant1", "correlation-key", "security.alert", "Test Alert");
|
||||
var incident = await _manager.GetOrCreateIncidentAsync("tenant1", "correlation-key", "security.alert", "Test Alert", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var acknowledged = await _manager.AcknowledgeAsync(
|
||||
"tenant1", incident.IncidentId, "operator", "Looking into it");
|
||||
var acknowledged = await _manager.AcknowledgeAsync("tenant1", incident.IncidentId, "operator", "Looking into it", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(acknowledged);
|
||||
@@ -175,7 +163,7 @@ public class InMemoryIncidentManagerTests
|
||||
public async Task AcknowledgeAsync_ReturnsNullForUnknownIncident()
|
||||
{
|
||||
// Act
|
||||
var result = await _manager.AcknowledgeAsync("tenant1", "unknown-id", "operator");
|
||||
var result = await _manager.AcknowledgeAsync("tenant1", "unknown-id", "operator", cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
@@ -185,11 +173,10 @@ public class InMemoryIncidentManagerTests
|
||||
public async Task AcknowledgeAsync_ReturnsNullForWrongTenant()
|
||||
{
|
||||
// Arrange
|
||||
var incident = await _manager.GetOrCreateIncidentAsync(
|
||||
"tenant1", "correlation-key", "security.alert", "Test Alert");
|
||||
var incident = await _manager.GetOrCreateIncidentAsync("tenant1", "correlation-key", "security.alert", "Test Alert", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _manager.AcknowledgeAsync("tenant2", incident.IncidentId, "operator");
|
||||
var result = await _manager.AcknowledgeAsync("tenant2", incident.IncidentId, "operator", cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
@@ -199,13 +186,12 @@ public class InMemoryIncidentManagerTests
|
||||
public async Task AcknowledgeAsync_DoesNotChangeResolvedIncident()
|
||||
{
|
||||
// Arrange
|
||||
var incident = await _manager.GetOrCreateIncidentAsync(
|
||||
"tenant1", "correlation-key", "security.alert", "Test Alert");
|
||||
var incident = await _manager.GetOrCreateIncidentAsync("tenant1", "correlation-key", "security.alert", "Test Alert", CancellationToken.None);
|
||||
|
||||
await _manager.ResolveAsync("tenant1", incident.IncidentId, "operator");
|
||||
await _manager.ResolveAsync("tenant1", incident.IncidentId, "operator", cancellationToken: CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _manager.AcknowledgeAsync("tenant1", incident.IncidentId, "operator2");
|
||||
var result = await _manager.AcknowledgeAsync("tenant1", incident.IncidentId, "operator2", cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
@@ -216,12 +202,10 @@ public class InMemoryIncidentManagerTests
|
||||
public async Task ResolveAsync_SetsResolvedStatus()
|
||||
{
|
||||
// Arrange
|
||||
var incident = await _manager.GetOrCreateIncidentAsync(
|
||||
"tenant1", "correlation-key", "security.alert", "Test Alert");
|
||||
var incident = await _manager.GetOrCreateIncidentAsync("tenant1", "correlation-key", "security.alert", "Test Alert", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var resolved = await _manager.ResolveAsync(
|
||||
"tenant1", incident.IncidentId, "operator", "Issue fixed");
|
||||
var resolved = await _manager.ResolveAsync("tenant1", incident.IncidentId, "operator", "Issue fixed", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(resolved);
|
||||
@@ -235,7 +219,7 @@ public class InMemoryIncidentManagerTests
|
||||
public async Task ResolveAsync_ReturnsNullForUnknownIncident()
|
||||
{
|
||||
// Act
|
||||
var result = await _manager.ResolveAsync("tenant1", "unknown-id", "operator");
|
||||
var result = await _manager.ResolveAsync("tenant1", "unknown-id", "operator", cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
@@ -245,11 +229,10 @@ public class InMemoryIncidentManagerTests
|
||||
public async Task GetAsync_ReturnsIncident()
|
||||
{
|
||||
// Arrange
|
||||
var created = await _manager.GetOrCreateIncidentAsync(
|
||||
"tenant1", "correlation-key", "security.alert", "Test Alert");
|
||||
var created = await _manager.GetOrCreateIncidentAsync("tenant1", "correlation-key", "security.alert", "Test Alert", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _manager.GetAsync("tenant1", created.IncidentId);
|
||||
var result = await _manager.GetAsync("tenant1", created.IncidentId, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
@@ -260,7 +243,7 @@ public class InMemoryIncidentManagerTests
|
||||
public async Task GetAsync_ReturnsNullForUnknownIncident()
|
||||
{
|
||||
// Act
|
||||
var result = await _manager.GetAsync("tenant1", "unknown-id");
|
||||
var result = await _manager.GetAsync("tenant1", "unknown-id", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
@@ -270,11 +253,10 @@ public class InMemoryIncidentManagerTests
|
||||
public async Task GetAsync_ReturnsNullForWrongTenant()
|
||||
{
|
||||
// Arrange
|
||||
var created = await _manager.GetOrCreateIncidentAsync(
|
||||
"tenant1", "correlation-key", "security.alert", "Test Alert");
|
||||
var created = await _manager.GetOrCreateIncidentAsync("tenant1", "correlation-key", "security.alert", "Test Alert", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _manager.GetAsync("tenant2", created.IncidentId);
|
||||
var result = await _manager.GetAsync("tenant2", created.IncidentId, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
@@ -284,12 +266,12 @@ public class InMemoryIncidentManagerTests
|
||||
public async Task ListAsync_ReturnsIncidentsForTenant()
|
||||
{
|
||||
// Arrange
|
||||
await _manager.GetOrCreateIncidentAsync("tenant1", "key1", "event1", "Alert 1");
|
||||
await _manager.GetOrCreateIncidentAsync("tenant1", "key2", "event2", "Alert 2");
|
||||
await _manager.GetOrCreateIncidentAsync("tenant2", "key3", "event3", "Alert 3");
|
||||
await _manager.GetOrCreateIncidentAsync("tenant1", "key1", "event1", "Alert 1", CancellationToken.None);
|
||||
await _manager.GetOrCreateIncidentAsync("tenant1", "key2", "event2", "Alert 2", CancellationToken.None);
|
||||
await _manager.GetOrCreateIncidentAsync("tenant2", "key3", "event3", "Alert 3", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _manager.ListAsync("tenant1");
|
||||
var result = await _manager.ListAsync("tenant1", cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, result.Count);
|
||||
@@ -300,15 +282,15 @@ public class InMemoryIncidentManagerTests
|
||||
public async Task ListAsync_FiltersbyStatus()
|
||||
{
|
||||
// Arrange
|
||||
var inc1 = await _manager.GetOrCreateIncidentAsync("tenant1", "key1", "event1", "Alert 1");
|
||||
var inc2 = await _manager.GetOrCreateIncidentAsync("tenant1", "key2", "event2", "Alert 2");
|
||||
await _manager.AcknowledgeAsync("tenant1", inc1.IncidentId, "operator");
|
||||
await _manager.ResolveAsync("tenant1", inc2.IncidentId, "operator");
|
||||
var inc1 = await _manager.GetOrCreateIncidentAsync("tenant1", "key1", "event1", "Alert 1", CancellationToken.None);
|
||||
var inc2 = await _manager.GetOrCreateIncidentAsync("tenant1", "key2", "event2", "Alert 2", CancellationToken.None);
|
||||
await _manager.AcknowledgeAsync("tenant1", inc1.IncidentId, "operator", cancellationToken: CancellationToken.None);
|
||||
await _manager.ResolveAsync("tenant1", inc2.IncidentId, "operator", cancellationToken: CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var openIncidents = await _manager.ListAsync("tenant1", IncidentStatus.Open);
|
||||
var acknowledgedIncidents = await _manager.ListAsync("tenant1", IncidentStatus.Acknowledged);
|
||||
var resolvedIncidents = await _manager.ListAsync("tenant1", IncidentStatus.Resolved);
|
||||
var openIncidents = await _manager.ListAsync("tenant1", IncidentStatus.Open, cancellationToken: CancellationToken.None);
|
||||
var acknowledgedIncidents = await _manager.ListAsync("tenant1", IncidentStatus.Acknowledged, cancellationToken: CancellationToken.None);
|
||||
var resolvedIncidents = await _manager.ListAsync("tenant1", IncidentStatus.Resolved, cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(openIncidents);
|
||||
@@ -320,21 +302,21 @@ public class InMemoryIncidentManagerTests
|
||||
public async Task ListAsync_OrdersByLastOccurrenceDescending()
|
||||
{
|
||||
// Arrange
|
||||
var inc1 = await _manager.GetOrCreateIncidentAsync("tenant1", "key1", "event1", "Alert 1");
|
||||
await _manager.RecordEventAsync("tenant1", inc1.IncidentId, "e1");
|
||||
var inc1 = await _manager.GetOrCreateIncidentAsync("tenant1", "key1", "event1", "Alert 1", CancellationToken.None);
|
||||
await _manager.RecordEventAsync("tenant1", inc1.IncidentId, "e1", CancellationToken.None);
|
||||
|
||||
_timeProvider.Advance(TimeSpan.FromMinutes(1));
|
||||
|
||||
var inc2 = await _manager.GetOrCreateIncidentAsync("tenant1", "key2", "event2", "Alert 2");
|
||||
await _manager.RecordEventAsync("tenant1", inc2.IncidentId, "e2");
|
||||
var inc2 = await _manager.GetOrCreateIncidentAsync("tenant1", "key2", "event2", "Alert 2", CancellationToken.None);
|
||||
await _manager.RecordEventAsync("tenant1", inc2.IncidentId, "e2", CancellationToken.None);
|
||||
|
||||
_timeProvider.Advance(TimeSpan.FromMinutes(1));
|
||||
|
||||
var inc3 = await _manager.GetOrCreateIncidentAsync("tenant1", "key3", "event3", "Alert 3");
|
||||
await _manager.RecordEventAsync("tenant1", inc3.IncidentId, "e3");
|
||||
var inc3 = await _manager.GetOrCreateIncidentAsync("tenant1", "key3", "event3", "Alert 3", CancellationToken.None);
|
||||
await _manager.RecordEventAsync("tenant1", inc3.IncidentId, "e3", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _manager.ListAsync("tenant1");
|
||||
var result = await _manager.ListAsync("tenant1", cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, result.Count);
|
||||
@@ -349,11 +331,11 @@ public class InMemoryIncidentManagerTests
|
||||
// Arrange
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
await _manager.GetOrCreateIncidentAsync("tenant1", $"key{i}", $"event{i}", $"Alert {i}");
|
||||
await _manager.GetOrCreateIncidentAsync("tenant1", $"key{i}", $"event{i}", $"Alert {i}", CancellationToken.None);
|
||||
}
|
||||
|
||||
// Act
|
||||
var result = await _manager.ListAsync("tenant1", limit: 5);
|
||||
var result = await _manager.ListAsync("tenant1", limit: 5, cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(5, result.Count);
|
||||
|
||||
@@ -30,8 +30,8 @@ public class InMemoryNotifyThrottlerTests
|
||||
public async Task RecordEventAsync_AddsEventToState()
|
||||
{
|
||||
// Act
|
||||
await _throttler.RecordEventAsync("tenant1", "key1");
|
||||
var result = await _throttler.CheckAsync("tenant1", "key1", null, null);
|
||||
await _throttler.RecordEventAsync("tenant1", "key1", CancellationToken.None);
|
||||
var result = await _throttler.CheckAsync("tenant1", "key1", null, null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsThrottled);
|
||||
@@ -42,7 +42,7 @@ public class InMemoryNotifyThrottlerTests
|
||||
public async Task CheckAsync_NoEvents_ReturnsNotThrottled()
|
||||
{
|
||||
// Act
|
||||
var result = await _throttler.CheckAsync("tenant1", "key1", null, null);
|
||||
var result = await _throttler.CheckAsync("tenant1", "key1", null, null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsThrottled);
|
||||
@@ -55,11 +55,11 @@ public class InMemoryNotifyThrottlerTests
|
||||
// Arrange
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
await _throttler.RecordEventAsync("tenant1", "key1");
|
||||
await _throttler.RecordEventAsync("tenant1", "key1", CancellationToken.None);
|
||||
}
|
||||
|
||||
// Act
|
||||
var result = await _throttler.CheckAsync("tenant1", "key1", null, null);
|
||||
var result = await _throttler.CheckAsync("tenant1", "key1", null, null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsThrottled);
|
||||
@@ -72,11 +72,11 @@ public class InMemoryNotifyThrottlerTests
|
||||
// Arrange
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
await _throttler.RecordEventAsync("tenant1", "key1");
|
||||
await _throttler.RecordEventAsync("tenant1", "key1", CancellationToken.None);
|
||||
}
|
||||
|
||||
// Act
|
||||
var result = await _throttler.CheckAsync("tenant1", "key1", null, null);
|
||||
var result = await _throttler.CheckAsync("tenant1", "key1", null, null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsThrottled);
|
||||
@@ -89,11 +89,11 @@ public class InMemoryNotifyThrottlerTests
|
||||
// Arrange
|
||||
for (int i = 0; i < 15; i++)
|
||||
{
|
||||
await _throttler.RecordEventAsync("tenant1", "key1");
|
||||
await _throttler.RecordEventAsync("tenant1", "key1", CancellationToken.None);
|
||||
}
|
||||
|
||||
// Act
|
||||
var result = await _throttler.CheckAsync("tenant1", "key1", null, null);
|
||||
var result = await _throttler.CheckAsync("tenant1", "key1", null, null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsThrottled);
|
||||
@@ -106,14 +106,14 @@ public class InMemoryNotifyThrottlerTests
|
||||
// Arrange
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
await _throttler.RecordEventAsync("tenant1", "key1");
|
||||
await _throttler.RecordEventAsync("tenant1", "key1", CancellationToken.None);
|
||||
}
|
||||
|
||||
// Move time forward past the window
|
||||
_timeProvider.Advance(TimeSpan.FromMinutes(6));
|
||||
|
||||
// Act
|
||||
var result = await _throttler.CheckAsync("tenant1", "key1", null, null);
|
||||
var result = await _throttler.CheckAsync("tenant1", "key1", null, null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsThrottled);
|
||||
@@ -126,7 +126,7 @@ public class InMemoryNotifyThrottlerTests
|
||||
// Arrange
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
await _throttler.RecordEventAsync("tenant1", "key1");
|
||||
await _throttler.RecordEventAsync("tenant1", "key1", CancellationToken.None);
|
||||
}
|
||||
|
||||
// Move time forward 2 minutes
|
||||
@@ -135,11 +135,11 @@ public class InMemoryNotifyThrottlerTests
|
||||
// Add more events
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
await _throttler.RecordEventAsync("tenant1", "key1");
|
||||
await _throttler.RecordEventAsync("tenant1", "key1", CancellationToken.None);
|
||||
}
|
||||
|
||||
// Act - check with 1 minute window (should only see recent 3)
|
||||
var result = await _throttler.CheckAsync("tenant1", "key1", TimeSpan.FromMinutes(1), null);
|
||||
var result = await _throttler.CheckAsync("tenant1", "key1", TimeSpan.FromMinutes(1), null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsThrottled);
|
||||
@@ -152,11 +152,11 @@ public class InMemoryNotifyThrottlerTests
|
||||
// Arrange
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
await _throttler.RecordEventAsync("tenant1", "key1");
|
||||
await _throttler.RecordEventAsync("tenant1", "key1", CancellationToken.None);
|
||||
}
|
||||
|
||||
// Act - check with max 3 events
|
||||
var result = await _throttler.CheckAsync("tenant1", "key1", null, 3);
|
||||
var result = await _throttler.CheckAsync("tenant1", "key1", null, 3, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsThrottled);
|
||||
@@ -167,7 +167,7 @@ public class InMemoryNotifyThrottlerTests
|
||||
public async Task CheckAsync_ThrottledReturnsResetTime()
|
||||
{
|
||||
// Arrange
|
||||
await _throttler.RecordEventAsync("tenant1", "key1");
|
||||
await _throttler.RecordEventAsync("tenant1", "key1", CancellationToken.None);
|
||||
|
||||
// Move time forward 2 minutes
|
||||
_timeProvider.Advance(TimeSpan.FromMinutes(2));
|
||||
@@ -175,11 +175,11 @@ public class InMemoryNotifyThrottlerTests
|
||||
// Fill up to threshold
|
||||
for (int i = 0; i < 9; i++)
|
||||
{
|
||||
await _throttler.RecordEventAsync("tenant1", "key1");
|
||||
await _throttler.RecordEventAsync("tenant1", "key1", CancellationToken.None);
|
||||
}
|
||||
|
||||
// Act
|
||||
var result = await _throttler.CheckAsync("tenant1", "key1", null, null);
|
||||
var result = await _throttler.CheckAsync("tenant1", "key1", null, null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsThrottled);
|
||||
@@ -194,12 +194,12 @@ public class InMemoryNotifyThrottlerTests
|
||||
// Arrange
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
await _throttler.RecordEventAsync("tenant1", "key1");
|
||||
await _throttler.RecordEventAsync("tenant1", "key1", CancellationToken.None);
|
||||
}
|
||||
|
||||
// Act
|
||||
var result1 = await _throttler.CheckAsync("tenant1", "key1", null, null);
|
||||
var result2 = await _throttler.CheckAsync("tenant1", "key2", null, null);
|
||||
var result1 = await _throttler.CheckAsync("tenant1", "key1", null, null, CancellationToken.None);
|
||||
var result2 = await _throttler.CheckAsync("tenant1", "key2", null, null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result1.IsThrottled);
|
||||
@@ -212,12 +212,12 @@ public class InMemoryNotifyThrottlerTests
|
||||
// Arrange
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
await _throttler.RecordEventAsync("tenant1", "key1");
|
||||
await _throttler.RecordEventAsync("tenant1", "key1", CancellationToken.None);
|
||||
}
|
||||
|
||||
// Act
|
||||
var result1 = await _throttler.CheckAsync("tenant1", "key1", null, null);
|
||||
var result2 = await _throttler.CheckAsync("tenant2", "key1", null, null);
|
||||
var result1 = await _throttler.CheckAsync("tenant1", "key1", null, null, CancellationToken.None);
|
||||
var result2 = await _throttler.CheckAsync("tenant2", "key1", null, null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result1.IsThrottled);
|
||||
@@ -230,18 +230,18 @@ public class InMemoryNotifyThrottlerTests
|
||||
// Arrange
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
await _throttler.RecordEventAsync("tenant1", "key1");
|
||||
await _throttler.RecordEventAsync("tenant1", "key1", CancellationToken.None);
|
||||
}
|
||||
|
||||
// Verify throttled
|
||||
var beforeClear = await _throttler.CheckAsync("tenant1", "key1", null, null);
|
||||
var beforeClear = await _throttler.CheckAsync("tenant1", "key1", null, null, CancellationToken.None);
|
||||
Assert.True(beforeClear.IsThrottled);
|
||||
|
||||
// Act
|
||||
await _throttler.ClearAsync("tenant1", "key1");
|
||||
await _throttler.ClearAsync("tenant1", "key1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var afterClear = await _throttler.CheckAsync("tenant1", "key1", null, null);
|
||||
var afterClear = await _throttler.CheckAsync("tenant1", "key1", null, null, CancellationToken.None);
|
||||
Assert.False(afterClear.IsThrottled);
|
||||
Assert.Equal(0, afterClear.RecentEventCount);
|
||||
}
|
||||
@@ -252,16 +252,16 @@ public class InMemoryNotifyThrottlerTests
|
||||
// Arrange
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
await _throttler.RecordEventAsync("tenant1", "key1");
|
||||
await _throttler.RecordEventAsync("tenant1", "key2");
|
||||
await _throttler.RecordEventAsync("tenant1", "key1", CancellationToken.None);
|
||||
await _throttler.RecordEventAsync("tenant1", "key2", CancellationToken.None);
|
||||
}
|
||||
|
||||
// Act
|
||||
await _throttler.ClearAsync("tenant1", "key1");
|
||||
await _throttler.ClearAsync("tenant1", "key1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var result1 = await _throttler.CheckAsync("tenant1", "key1", null, null);
|
||||
var result2 = await _throttler.CheckAsync("tenant1", "key2", null, null);
|
||||
var result1 = await _throttler.CheckAsync("tenant1", "key1", null, null, CancellationToken.None);
|
||||
var result2 = await _throttler.CheckAsync("tenant1", "key2", null, null, CancellationToken.None);
|
||||
|
||||
Assert.False(result1.IsThrottled);
|
||||
Assert.True(result2.IsThrottled);
|
||||
|
||||
@@ -43,7 +43,7 @@ public class OperatorOverrideServiceTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var @override = await _service.CreateOverrideAsync("tenant1", request, "admin@example.com");
|
||||
var @override = await _service.CreateOverrideAsync("tenant1", request, "admin@example.com", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(@override);
|
||||
@@ -69,7 +69,7 @@ public class OperatorOverrideServiceTests
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<ArgumentException>(() =>
|
||||
_service.CreateOverrideAsync("tenant1", request, "admin"));
|
||||
_service.CreateOverrideAsync("tenant1", request, "admin", CancellationToken.None));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -85,7 +85,7 @@ public class OperatorOverrideServiceTests
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<ArgumentException>(() =>
|
||||
_service.CreateOverrideAsync("tenant1", request, "admin"));
|
||||
_service.CreateOverrideAsync("tenant1", request, "admin", CancellationToken.None));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -100,7 +100,7 @@ public class OperatorOverrideServiceTests
|
||||
};
|
||||
|
||||
// Act
|
||||
await _service.CreateOverrideAsync("tenant1", request, "admin");
|
||||
await _service.CreateOverrideAsync("tenant1", request, "admin", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
_auditLogger.Verify(a => a.LogAsync(
|
||||
@@ -120,10 +120,10 @@ public class OperatorOverrideServiceTests
|
||||
Type = OverrideType.Throttle,
|
||||
Reason = "Test override",
|
||||
Duration = TimeSpan.FromHours(1)
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var retrieved = await _service.GetOverrideAsync("tenant1", created.OverrideId);
|
||||
var retrieved = await _service.GetOverrideAsync("tenant1", created.OverrideId, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(retrieved);
|
||||
@@ -139,13 +139,13 @@ public class OperatorOverrideServiceTests
|
||||
Type = OverrideType.All,
|
||||
Reason = "Short override",
|
||||
Duration = TimeSpan.FromMinutes(30)
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Advance time past expiry
|
||||
_timeProvider.Advance(TimeSpan.FromMinutes(31));
|
||||
|
||||
// Act
|
||||
var retrieved = await _service.GetOverrideAsync("tenant1", created.OverrideId);
|
||||
var retrieved = await _service.GetOverrideAsync("tenant1", created.OverrideId, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(retrieved);
|
||||
@@ -161,20 +161,20 @@ public class OperatorOverrideServiceTests
|
||||
Type = OverrideType.All,
|
||||
Reason = "Override 1",
|
||||
Duration = TimeSpan.FromHours(2)
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
await _service.CreateOverrideAsync("tenant1", new OperatorOverrideCreate
|
||||
{
|
||||
Type = OverrideType.QuietHours,
|
||||
Reason = "Override 2 (short)",
|
||||
Duration = TimeSpan.FromMinutes(10)
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Advance time so second override expires
|
||||
_timeProvider.Advance(TimeSpan.FromMinutes(15));
|
||||
|
||||
// Act
|
||||
var active = await _service.ListActiveOverridesAsync("tenant1");
|
||||
var active = await _service.ListActiveOverridesAsync("tenant1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Single(active);
|
||||
@@ -190,15 +190,15 @@ public class OperatorOverrideServiceTests
|
||||
Type = OverrideType.All,
|
||||
Reason = "To be revoked",
|
||||
Duration = TimeSpan.FromHours(1)
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var revoked = await _service.RevokeOverrideAsync("tenant1", created.OverrideId, "supervisor", "No longer needed");
|
||||
var revoked = await _service.RevokeOverrideAsync("tenant1", created.OverrideId, "supervisor", "No longer needed", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(revoked);
|
||||
|
||||
var retrieved = await _service.GetOverrideAsync("tenant1", created.OverrideId);
|
||||
var retrieved = await _service.GetOverrideAsync("tenant1", created.OverrideId, CancellationToken.None);
|
||||
Assert.NotNull(retrieved);
|
||||
Assert.Equal(OverrideStatus.Revoked, retrieved.Status);
|
||||
Assert.Equal("supervisor", retrieved.RevokedBy);
|
||||
@@ -214,10 +214,10 @@ public class OperatorOverrideServiceTests
|
||||
Type = OverrideType.All,
|
||||
Reason = "To be revoked",
|
||||
Duration = TimeSpan.FromHours(1)
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
await _service.RevokeOverrideAsync("tenant1", created.OverrideId, "supervisor", "Testing");
|
||||
await _service.RevokeOverrideAsync("tenant1", created.OverrideId, "supervisor", "Testing", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
_auditLogger.Verify(a => a.LogAsync(
|
||||
@@ -236,10 +236,10 @@ public class OperatorOverrideServiceTests
|
||||
Type = OverrideType.QuietHours,
|
||||
Reason = "Deployment override",
|
||||
Duration = TimeSpan.FromHours(1)
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _service.CheckOverrideAsync("tenant1", "deployment.complete", null);
|
||||
var result = await _service.CheckOverrideAsync("tenant1", "deployment.complete", null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.HasOverride);
|
||||
@@ -251,7 +251,7 @@ public class OperatorOverrideServiceTests
|
||||
public async Task CheckOverrideAsync_ReturnsNoOverrideWhenNoneMatch()
|
||||
{
|
||||
// Act
|
||||
var result = await _service.CheckOverrideAsync("tenant1", "event.test", null);
|
||||
var result = await _service.CheckOverrideAsync("tenant1", "event.test", null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.HasOverride);
|
||||
@@ -268,11 +268,11 @@ public class OperatorOverrideServiceTests
|
||||
Reason = "Only for deployments",
|
||||
Duration = TimeSpan.FromHours(1),
|
||||
EventKinds = ["deployment.", "release."]
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var deploymentResult = await _service.CheckOverrideAsync("tenant1", "deployment.started", null);
|
||||
var otherResult = await _service.CheckOverrideAsync("tenant1", "vulnerability.found", null);
|
||||
var deploymentResult = await _service.CheckOverrideAsync("tenant1", "deployment.started", null, CancellationToken.None);
|
||||
var otherResult = await _service.CheckOverrideAsync("tenant1", "vulnerability.found", null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(deploymentResult.HasOverride);
|
||||
@@ -289,11 +289,11 @@ public class OperatorOverrideServiceTests
|
||||
Reason = "Specific incident",
|
||||
Duration = TimeSpan.FromHours(1),
|
||||
CorrelationKeys = ["incident-123", "incident-456"]
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var matchingResult = await _service.CheckOverrideAsync("tenant1", "event.test", "incident-123");
|
||||
var nonMatchingResult = await _service.CheckOverrideAsync("tenant1", "event.test", "incident-789");
|
||||
var matchingResult = await _service.CheckOverrideAsync("tenant1", "event.test", "incident-123", CancellationToken.None);
|
||||
var nonMatchingResult = await _service.CheckOverrideAsync("tenant1", "event.test", "incident-789", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(matchingResult.HasOverride);
|
||||
@@ -310,14 +310,14 @@ public class OperatorOverrideServiceTests
|
||||
Reason = "Limited use override",
|
||||
Duration = TimeSpan.FromHours(1),
|
||||
MaxUsageCount = 5
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
await _service.RecordOverrideUsageAsync("tenant1", created.OverrideId, "event.test");
|
||||
await _service.RecordOverrideUsageAsync("tenant1", created.OverrideId, "event.test");
|
||||
await _service.RecordOverrideUsageAsync("tenant1", created.OverrideId, "event.test", CancellationToken.None);
|
||||
await _service.RecordOverrideUsageAsync("tenant1", created.OverrideId, "event.test", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var updated = await _service.GetOverrideAsync("tenant1", created.OverrideId);
|
||||
var updated = await _service.GetOverrideAsync("tenant1", created.OverrideId, CancellationToken.None);
|
||||
Assert.NotNull(updated);
|
||||
Assert.Equal(2, updated.UsageCount);
|
||||
}
|
||||
@@ -332,14 +332,14 @@ public class OperatorOverrideServiceTests
|
||||
Reason = "Single use override",
|
||||
Duration = TimeSpan.FromHours(1),
|
||||
MaxUsageCount = 2
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
await _service.RecordOverrideUsageAsync("tenant1", created.OverrideId, "event.test");
|
||||
await _service.RecordOverrideUsageAsync("tenant1", created.OverrideId, "event.test");
|
||||
await _service.RecordOverrideUsageAsync("tenant1", created.OverrideId, "event.test", CancellationToken.None);
|
||||
await _service.RecordOverrideUsageAsync("tenant1", created.OverrideId, "event.test", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var updated = await _service.GetOverrideAsync("tenant1", created.OverrideId);
|
||||
var updated = await _service.GetOverrideAsync("tenant1", created.OverrideId, CancellationToken.None);
|
||||
Assert.NotNull(updated);
|
||||
Assert.Equal(OverrideStatus.Exhausted, updated.Status);
|
||||
}
|
||||
@@ -353,10 +353,10 @@ public class OperatorOverrideServiceTests
|
||||
Type = OverrideType.All,
|
||||
Reason = "Override for audit test",
|
||||
Duration = TimeSpan.FromHours(1)
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
await _service.RecordOverrideUsageAsync("tenant1", created.OverrideId, "event.test");
|
||||
await _service.RecordOverrideUsageAsync("tenant1", created.OverrideId, "event.test", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
_auditLogger.Verify(a => a.LogAsync(
|
||||
@@ -376,12 +376,12 @@ public class OperatorOverrideServiceTests
|
||||
Reason = "Single use",
|
||||
Duration = TimeSpan.FromHours(1),
|
||||
MaxUsageCount = 1
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
await _service.RecordOverrideUsageAsync("tenant1", created.OverrideId, "event.test");
|
||||
await _service.RecordOverrideUsageAsync("tenant1", created.OverrideId, "event.test", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _service.CheckOverrideAsync("tenant1", "event.other", null);
|
||||
var result = await _service.CheckOverrideAsync("tenant1", "event.other", null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.HasOverride);
|
||||
@@ -401,7 +401,7 @@ public class OperatorOverrideServiceTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var created = await _service.CreateOverrideAsync("tenant1", request, "admin");
|
||||
var created = await _service.CreateOverrideAsync("tenant1", request, "admin", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(futureTime, created.EffectiveFrom);
|
||||
@@ -419,10 +419,10 @@ public class OperatorOverrideServiceTests
|
||||
Reason = "Future override",
|
||||
Duration = TimeSpan.FromHours(2),
|
||||
EffectiveFrom = futureTime
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act (before effective time)
|
||||
var result = await _service.CheckOverrideAsync("tenant1", "event.test", null);
|
||||
var result = await _service.CheckOverrideAsync("tenant1", "event.test", null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.HasOverride);
|
||||
@@ -437,10 +437,10 @@ public class OperatorOverrideServiceTests
|
||||
Type = OverrideType.QuietHours | OverrideType.Throttle, // Multiple types
|
||||
Reason = "Partial override",
|
||||
Duration = TimeSpan.FromHours(1)
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _service.CheckOverrideAsync("tenant1", "event.test", null);
|
||||
var result = await _service.CheckOverrideAsync("tenant1", "event.test", null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.HasOverride);
|
||||
|
||||
@@ -42,7 +42,7 @@ public class QuietHourCalendarServiceTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var calendar = await _service.CreateCalendarAsync("tenant1", request, "admin@example.com");
|
||||
var calendar = await _service.CreateCalendarAsync("tenant1", request, "admin@example.com", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(calendar);
|
||||
@@ -64,7 +64,7 @@ public class QuietHourCalendarServiceTests
|
||||
};
|
||||
|
||||
// Act
|
||||
await _service.CreateCalendarAsync("tenant1", request, "admin");
|
||||
await _service.CreateCalendarAsync("tenant1", request, "admin", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
_auditLogger.Verify(a => a.LogAsync(
|
||||
@@ -79,12 +79,12 @@ public class QuietHourCalendarServiceTests
|
||||
public async Task ListCalendarsAsync_ReturnsAllCalendarsForTenant()
|
||||
{
|
||||
// Arrange
|
||||
await _service.CreateCalendarAsync("tenant1", new QuietHourCalendarCreate { Name = "Calendar 1", Priority = 50 }, "admin");
|
||||
await _service.CreateCalendarAsync("tenant1", new QuietHourCalendarCreate { Name = "Calendar 2", Priority = 100 }, "admin");
|
||||
await _service.CreateCalendarAsync("tenant2", new QuietHourCalendarCreate { Name = "Other Tenant" }, "admin");
|
||||
await _service.CreateCalendarAsync("tenant1", new QuietHourCalendarCreate { Name = "Calendar 1", Priority = 50 }, "admin", CancellationToken.None);
|
||||
await _service.CreateCalendarAsync("tenant1", new QuietHourCalendarCreate { Name = "Calendar 2", Priority = 100 }, "admin", CancellationToken.None);
|
||||
await _service.CreateCalendarAsync("tenant2", new QuietHourCalendarCreate { Name = "Other Tenant" }, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var calendars = await _service.ListCalendarsAsync("tenant1");
|
||||
var calendars = await _service.ListCalendarsAsync("tenant1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, calendars.Count);
|
||||
@@ -96,10 +96,10 @@ public class QuietHourCalendarServiceTests
|
||||
public async Task GetCalendarAsync_ReturnsCalendarIfExists()
|
||||
{
|
||||
// Arrange
|
||||
var created = await _service.CreateCalendarAsync("tenant1", new QuietHourCalendarCreate { Name = "Test" }, "admin");
|
||||
var created = await _service.CreateCalendarAsync("tenant1", new QuietHourCalendarCreate { Name = "Test" }, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var retrieved = await _service.GetCalendarAsync("tenant1", created.CalendarId);
|
||||
var retrieved = await _service.GetCalendarAsync("tenant1", created.CalendarId, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(retrieved);
|
||||
@@ -111,7 +111,7 @@ public class QuietHourCalendarServiceTests
|
||||
public async Task GetCalendarAsync_ReturnsNullIfNotExists()
|
||||
{
|
||||
// Act
|
||||
var result = await _service.GetCalendarAsync("tenant1", "nonexistent");
|
||||
var result = await _service.GetCalendarAsync("tenant1", "nonexistent", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
@@ -121,7 +121,7 @@ public class QuietHourCalendarServiceTests
|
||||
public async Task UpdateCalendarAsync_UpdatesExistingCalendar()
|
||||
{
|
||||
// Arrange
|
||||
var created = await _service.CreateCalendarAsync("tenant1", new QuietHourCalendarCreate { Name = "Original" }, "admin");
|
||||
var created = await _service.CreateCalendarAsync("tenant1", new QuietHourCalendarCreate { Name = "Original" }, "admin", CancellationToken.None);
|
||||
|
||||
var update = new QuietHourCalendarUpdate
|
||||
{
|
||||
@@ -130,7 +130,7 @@ public class QuietHourCalendarServiceTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var updated = await _service.UpdateCalendarAsync("tenant1", created.CalendarId, update, "other-admin");
|
||||
var updated = await _service.UpdateCalendarAsync("tenant1", created.CalendarId, update, "other-admin", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(updated);
|
||||
@@ -143,14 +143,14 @@ public class QuietHourCalendarServiceTests
|
||||
public async Task DeleteCalendarAsync_RemovesCalendar()
|
||||
{
|
||||
// Arrange
|
||||
var created = await _service.CreateCalendarAsync("tenant1", new QuietHourCalendarCreate { Name = "ToDelete" }, "admin");
|
||||
var created = await _service.CreateCalendarAsync("tenant1", new QuietHourCalendarCreate { Name = "ToDelete" }, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var deleted = await _service.DeleteCalendarAsync("tenant1", created.CalendarId, "admin");
|
||||
var deleted = await _service.DeleteCalendarAsync("tenant1", created.CalendarId, "admin", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(deleted);
|
||||
var retrieved = await _service.GetCalendarAsync("tenant1", created.CalendarId);
|
||||
var retrieved = await _service.GetCalendarAsync("tenant1", created.CalendarId, CancellationToken.None);
|
||||
Assert.Null(retrieved);
|
||||
}
|
||||
|
||||
@@ -170,13 +170,13 @@ public class QuietHourCalendarServiceTests
|
||||
EndTime = "08:00"
|
||||
}
|
||||
]
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Set time to 23:00 (11pm) - within quiet hours
|
||||
_timeProvider.SetUtcNow(new DateTimeOffset(2024, 1, 15, 23, 0, 0, TimeSpan.Zero));
|
||||
|
||||
// Act
|
||||
var result = await _service.EvaluateCalendarsAsync("tenant1", "vulnerability.found", null);
|
||||
var result = await _service.EvaluateCalendarsAsync("tenant1", "vulnerability.found", null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsSuppressed);
|
||||
@@ -200,12 +200,12 @@ public class QuietHourCalendarServiceTests
|
||||
EndTime = "08:00"
|
||||
}
|
||||
]
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Time is 2pm (14:00) - outside quiet hours
|
||||
|
||||
// Act
|
||||
var result = await _service.EvaluateCalendarsAsync("tenant1", "vulnerability.found", null);
|
||||
var result = await _service.EvaluateCalendarsAsync("tenant1", "vulnerability.found", null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsSuppressed);
|
||||
@@ -228,14 +228,14 @@ public class QuietHourCalendarServiceTests
|
||||
EndTime = "08:00"
|
||||
}
|
||||
]
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Set time to 23:00 (11pm) - within quiet hours
|
||||
_timeProvider.SetUtcNow(new DateTimeOffset(2024, 1, 15, 23, 0, 0, TimeSpan.Zero));
|
||||
|
||||
// Act
|
||||
var criticalResult = await _service.EvaluateCalendarsAsync("tenant1", "critical.security.breach", null);
|
||||
var normalResult = await _service.EvaluateCalendarsAsync("tenant1", "info.scan.complete", null);
|
||||
var criticalResult = await _service.EvaluateCalendarsAsync("tenant1", "critical.security.breach", null, CancellationToken.None);
|
||||
var normalResult = await _service.EvaluateCalendarsAsync("tenant1", "info.scan.complete", null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(criticalResult.IsSuppressed); // Critical events not suppressed
|
||||
@@ -259,11 +259,11 @@ public class QuietHourCalendarServiceTests
|
||||
EndTime = "23:59"
|
||||
}
|
||||
]
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var scanResult = await _service.EvaluateCalendarsAsync("tenant1", "scan.complete", null);
|
||||
var otherResult = await _service.EvaluateCalendarsAsync("tenant1", "vulnerability.found", null);
|
||||
var scanResult = await _service.EvaluateCalendarsAsync("tenant1", "scan.complete", null, CancellationToken.None);
|
||||
var otherResult = await _service.EvaluateCalendarsAsync("tenant1", "vulnerability.found", null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(scanResult.IsSuppressed);
|
||||
@@ -287,11 +287,11 @@ public class QuietHourCalendarServiceTests
|
||||
EndTime = "23:59"
|
||||
}
|
||||
]
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var teamAResult = await _service.EvaluateCalendarsAsync("tenant1", "event.test", ["team-a"]);
|
||||
var teamCResult = await _service.EvaluateCalendarsAsync("tenant1", "event.test", ["team-c"]);
|
||||
var teamAResult = await _service.EvaluateCalendarsAsync("tenant1", "event.test", ["team-a"], CancellationToken.None);
|
||||
var teamCResult = await _service.EvaluateCalendarsAsync("tenant1", "event.test", ["team-c"], CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(teamAResult.IsSuppressed);
|
||||
@@ -315,14 +315,14 @@ public class QuietHourCalendarServiceTests
|
||||
DaysOfWeek = [0, 6] // Sunday and Saturday
|
||||
}
|
||||
]
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Monday (current time is Monday)
|
||||
var mondayResult = await _service.EvaluateCalendarsAsync("tenant1", "event.test", null);
|
||||
var mondayResult = await _service.EvaluateCalendarsAsync("tenant1", "event.test", null, CancellationToken.None);
|
||||
|
||||
// Set to Saturday
|
||||
_timeProvider.SetUtcNow(new DateTimeOffset(2024, 1, 20, 14, 0, 0, TimeSpan.Zero));
|
||||
var saturdayResult = await _service.EvaluateCalendarsAsync("tenant1", "event.test", null);
|
||||
var saturdayResult = await _service.EvaluateCalendarsAsync("tenant1", "event.test", null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(mondayResult.IsSuppressed);
|
||||
@@ -345,13 +345,13 @@ public class QuietHourCalendarServiceTests
|
||||
EndTime = "23:59"
|
||||
}
|
||||
]
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Disable the calendar
|
||||
await _service.UpdateCalendarAsync("tenant1", created.CalendarId, new QuietHourCalendarUpdate { Enabled = false }, "admin");
|
||||
await _service.UpdateCalendarAsync("tenant1", created.CalendarId, new QuietHourCalendarUpdate { Enabled = false }, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _service.EvaluateCalendarsAsync("tenant1", "event.test", null);
|
||||
var result = await _service.EvaluateCalendarsAsync("tenant1", "event.test", null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsSuppressed);
|
||||
@@ -375,7 +375,7 @@ public class QuietHourCalendarServiceTests
|
||||
EndTime = "23:59"
|
||||
}
|
||||
]
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
await _service.CreateCalendarAsync("tenant1", new QuietHourCalendarCreate
|
||||
{
|
||||
@@ -390,10 +390,10 @@ public class QuietHourCalendarServiceTests
|
||||
EndTime = "23:59"
|
||||
}
|
||||
]
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _service.EvaluateCalendarsAsync("tenant1", "critical.alert", null);
|
||||
var result = await _service.EvaluateCalendarsAsync("tenant1", "critical.alert", null, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsSuppressed);
|
||||
|
||||
@@ -34,7 +34,7 @@ public class QuietHoursEvaluatorTests
|
||||
_options.Schedule = null;
|
||||
|
||||
// Act
|
||||
var result = await _evaluator.EvaluateAsync("tenant1", "test.event");
|
||||
var result = await _evaluator.EvaluateAsync("tenant1", "test.event", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsSuppressed);
|
||||
@@ -47,7 +47,7 @@ public class QuietHoursEvaluatorTests
|
||||
_options.Schedule = new QuietHoursSchedule { Enabled = false };
|
||||
|
||||
// Act
|
||||
var result = await _evaluator.EvaluateAsync("tenant1", "test.event");
|
||||
var result = await _evaluator.EvaluateAsync("tenant1", "test.event", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsSuppressed);
|
||||
@@ -66,7 +66,7 @@ public class QuietHoursEvaluatorTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _evaluator.EvaluateAsync("tenant1", "test.event");
|
||||
var result = await _evaluator.EvaluateAsync("tenant1", "test.event", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsSuppressed);
|
||||
@@ -86,7 +86,7 @@ public class QuietHoursEvaluatorTests
|
||||
var evaluator = CreateEvaluator();
|
||||
|
||||
// Act
|
||||
var result = await evaluator.EvaluateAsync("tenant1", "test.event");
|
||||
var result = await evaluator.EvaluateAsync("tenant1", "test.event", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsSuppressed);
|
||||
@@ -108,7 +108,7 @@ public class QuietHoursEvaluatorTests
|
||||
var evaluator = CreateEvaluator();
|
||||
|
||||
// Act
|
||||
var result = await evaluator.EvaluateAsync("tenant1", "test.event");
|
||||
var result = await evaluator.EvaluateAsync("tenant1", "test.event", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsSuppressed);
|
||||
@@ -128,7 +128,7 @@ public class QuietHoursEvaluatorTests
|
||||
var evaluator = CreateEvaluator();
|
||||
|
||||
// Act
|
||||
var result = await evaluator.EvaluateAsync("tenant1", "test.event");
|
||||
var result = await evaluator.EvaluateAsync("tenant1", "test.event", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsSuppressed);
|
||||
@@ -148,7 +148,7 @@ public class QuietHoursEvaluatorTests
|
||||
var evaluator = CreateEvaluator();
|
||||
|
||||
// Act
|
||||
var result = await evaluator.EvaluateAsync("tenant1", "test.event");
|
||||
var result = await evaluator.EvaluateAsync("tenant1", "test.event", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsSuppressed);
|
||||
@@ -168,7 +168,7 @@ public class QuietHoursEvaluatorTests
|
||||
var evaluator = CreateEvaluator();
|
||||
|
||||
// Act
|
||||
var result = await evaluator.EvaluateAsync("tenant1", "test.event");
|
||||
var result = await evaluator.EvaluateAsync("tenant1", "test.event", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsSuppressed);
|
||||
@@ -189,7 +189,7 @@ public class QuietHoursEvaluatorTests
|
||||
var evaluator = CreateEvaluator();
|
||||
|
||||
// Act
|
||||
var result = await evaluator.EvaluateAsync("tenant1", "test.event");
|
||||
var result = await evaluator.EvaluateAsync("tenant1", "test.event", CancellationToken.None);
|
||||
|
||||
// Assert - Wednesday is not in the list
|
||||
Assert.False(result.IsSuppressed);
|
||||
@@ -210,7 +210,7 @@ public class QuietHoursEvaluatorTests
|
||||
var evaluator = CreateEvaluator();
|
||||
|
||||
// Act
|
||||
var result = await evaluator.EvaluateAsync("tenant1", "test.event");
|
||||
var result = await evaluator.EvaluateAsync("tenant1", "test.event", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsSuppressed);
|
||||
@@ -231,7 +231,7 @@ public class QuietHoursEvaluatorTests
|
||||
var evaluator = CreateEvaluator();
|
||||
|
||||
// Act
|
||||
var result = await evaluator.EvaluateAsync("tenant1", "security.alert");
|
||||
var result = await evaluator.EvaluateAsync("tenant1", "security.alert", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsSuppressed);
|
||||
@@ -251,10 +251,10 @@ public class QuietHoursEvaluatorTests
|
||||
Description = "Scheduled maintenance"
|
||||
};
|
||||
|
||||
await _evaluator.AddMaintenanceWindowAsync("tenant1", window);
|
||||
await _evaluator.AddMaintenanceWindowAsync("tenant1", window, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _evaluator.EvaluateAsync("tenant1", "test.event");
|
||||
var result = await _evaluator.EvaluateAsync("tenant1", "test.event", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsSuppressed);
|
||||
@@ -276,10 +276,10 @@ public class QuietHoursEvaluatorTests
|
||||
Description = "Future maintenance"
|
||||
};
|
||||
|
||||
await _evaluator.AddMaintenanceWindowAsync("tenant1", window);
|
||||
await _evaluator.AddMaintenanceWindowAsync("tenant1", window, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _evaluator.EvaluateAsync("tenant1", "test.event");
|
||||
var result = await _evaluator.EvaluateAsync("tenant1", "test.event", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsSuppressed);
|
||||
@@ -298,10 +298,10 @@ public class QuietHoursEvaluatorTests
|
||||
EndTime = now.AddHours(1)
|
||||
};
|
||||
|
||||
await _evaluator.AddMaintenanceWindowAsync("tenant1", window);
|
||||
await _evaluator.AddMaintenanceWindowAsync("tenant1", window, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _evaluator.EvaluateAsync("tenant2", "test.event");
|
||||
var result = await _evaluator.EvaluateAsync("tenant2", "test.event", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsSuppressed);
|
||||
@@ -321,10 +321,10 @@ public class QuietHoursEvaluatorTests
|
||||
AffectedEventKinds = ["scanner", "monitor"]
|
||||
};
|
||||
|
||||
await _evaluator.AddMaintenanceWindowAsync("tenant1", window);
|
||||
await _evaluator.AddMaintenanceWindowAsync("tenant1", window, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _evaluator.EvaluateAsync("tenant1", "scanner.complete");
|
||||
var result = await _evaluator.EvaluateAsync("tenant1", "scanner.complete", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsSuppressed);
|
||||
@@ -344,10 +344,10 @@ public class QuietHoursEvaluatorTests
|
||||
AffectedEventKinds = ["scanner", "monitor"]
|
||||
};
|
||||
|
||||
await _evaluator.AddMaintenanceWindowAsync("tenant1", window);
|
||||
await _evaluator.AddMaintenanceWindowAsync("tenant1", window, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _evaluator.EvaluateAsync("tenant1", "security.alert");
|
||||
var result = await _evaluator.EvaluateAsync("tenant1", "security.alert", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsSuppressed);
|
||||
@@ -367,10 +367,10 @@ public class QuietHoursEvaluatorTests
|
||||
};
|
||||
|
||||
// Act
|
||||
await _evaluator.AddMaintenanceWindowAsync("tenant1", window);
|
||||
await _evaluator.AddMaintenanceWindowAsync("tenant1", window, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var windows = await _evaluator.ListMaintenanceWindowsAsync("tenant1");
|
||||
var windows = await _evaluator.ListMaintenanceWindowsAsync("tenant1", CancellationToken.None);
|
||||
Assert.Single(windows);
|
||||
Assert.Equal("maint-1", windows[0].WindowId);
|
||||
}
|
||||
@@ -388,13 +388,13 @@ public class QuietHoursEvaluatorTests
|
||||
EndTime = now.AddHours(2)
|
||||
};
|
||||
|
||||
await _evaluator.AddMaintenanceWindowAsync("tenant1", window);
|
||||
await _evaluator.AddMaintenanceWindowAsync("tenant1", window, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
await _evaluator.RemoveMaintenanceWindowAsync("tenant1", "maint-1");
|
||||
await _evaluator.RemoveMaintenanceWindowAsync("tenant1", "maint-1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var windows = await _evaluator.ListMaintenanceWindowsAsync("tenant1");
|
||||
var windows = await _evaluator.ListMaintenanceWindowsAsync("tenant1", CancellationToken.None);
|
||||
Assert.Empty(windows);
|
||||
}
|
||||
|
||||
@@ -419,11 +419,11 @@ public class QuietHoursEvaluatorTests
|
||||
EndTime = now.AddHours(-1)
|
||||
};
|
||||
|
||||
await _evaluator.AddMaintenanceWindowAsync("tenant1", activeWindow);
|
||||
await _evaluator.AddMaintenanceWindowAsync("tenant1", expiredWindow);
|
||||
await _evaluator.AddMaintenanceWindowAsync("tenant1", activeWindow, CancellationToken.None);
|
||||
await _evaluator.AddMaintenanceWindowAsync("tenant1", expiredWindow, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var windows = await _evaluator.ListMaintenanceWindowsAsync("tenant1");
|
||||
var windows = await _evaluator.ListMaintenanceWindowsAsync("tenant1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Single(windows);
|
||||
@@ -454,10 +454,10 @@ public class QuietHoursEvaluatorTests
|
||||
Description = "System upgrade"
|
||||
};
|
||||
|
||||
await evaluator.AddMaintenanceWindowAsync("tenant1", window);
|
||||
await evaluator.AddMaintenanceWindowAsync("tenant1", window, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await evaluator.EvaluateAsync("tenant1", "test.event");
|
||||
var result = await evaluator.EvaluateAsync("tenant1", "test.event", CancellationToken.None);
|
||||
|
||||
// Assert - maintenance should take priority
|
||||
Assert.True(result.IsSuppressed);
|
||||
|
||||
@@ -28,10 +28,10 @@ public class SuppressionAuditLoggerTests
|
||||
var entry = CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated);
|
||||
|
||||
// Act
|
||||
await _logger.LogAsync(entry);
|
||||
await _logger.LogAsync(entry, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var results = await _logger.QueryAsync(new SuppressionAuditQuery { TenantId = "tenant1" });
|
||||
var results = await _logger.QueryAsync(new SuppressionAuditQuery { TenantId = "tenant1" }, CancellationToken.None);
|
||||
Assert.Single(results);
|
||||
Assert.Equal(entry.EntryId, results[0].EntryId);
|
||||
}
|
||||
@@ -40,7 +40,7 @@ public class SuppressionAuditLoggerTests
|
||||
public async Task QueryAsync_ReturnsEmptyForUnknownTenant()
|
||||
{
|
||||
// Act
|
||||
var results = await _logger.QueryAsync(new SuppressionAuditQuery { TenantId = "nonexistent" });
|
||||
var results = await _logger.QueryAsync(new SuppressionAuditQuery { TenantId = "nonexistent" }, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(results);
|
||||
@@ -51,9 +51,9 @@ public class SuppressionAuditLoggerTests
|
||||
{
|
||||
// Arrange
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated, now.AddHours(-3)));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarUpdated, now.AddHours(-1)));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarDeleted, now));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated, now.AddHours(-3)), CancellationToken.None);
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarUpdated, now.AddHours(-1)), CancellationToken.None);
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarDeleted, now), CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var results = await _logger.QueryAsync(new SuppressionAuditQuery
|
||||
@@ -61,7 +61,7 @@ public class SuppressionAuditLoggerTests
|
||||
TenantId = "tenant1",
|
||||
From = now.AddHours(-2),
|
||||
To = now.AddMinutes(-30)
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Single(results);
|
||||
@@ -72,16 +72,16 @@ public class SuppressionAuditLoggerTests
|
||||
public async Task QueryAsync_FiltersByAction()
|
||||
{
|
||||
// Arrange
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarUpdated));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.ThrottleConfigUpdated));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated), CancellationToken.None);
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarUpdated), CancellationToken.None);
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.ThrottleConfigUpdated), CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var results = await _logger.QueryAsync(new SuppressionAuditQuery
|
||||
{
|
||||
TenantId = "tenant1",
|
||||
Actions = [SuppressionAuditAction.CalendarCreated, SuppressionAuditAction.CalendarUpdated]
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, results.Count);
|
||||
@@ -92,16 +92,16 @@ public class SuppressionAuditLoggerTests
|
||||
public async Task QueryAsync_FiltersByActor()
|
||||
{
|
||||
// Arrange
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated, actor: "admin1"));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarUpdated, actor: "admin2"));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarDeleted, actor: "admin1"));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated, actor: "admin1"), CancellationToken.None);
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarUpdated, actor: "admin2"), CancellationToken.None);
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarDeleted, actor: "admin1"), CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var results = await _logger.QueryAsync(new SuppressionAuditQuery
|
||||
{
|
||||
TenantId = "tenant1",
|
||||
Actor = "admin1"
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, results.Count);
|
||||
@@ -112,15 +112,15 @@ public class SuppressionAuditLoggerTests
|
||||
public async Task QueryAsync_FiltersByResourceType()
|
||||
{
|
||||
// Arrange
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated, resourceType: "QuietHourCalendar"));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.ThrottleConfigUpdated, resourceType: "TenantThrottleConfig"));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated, resourceType: "QuietHourCalendar"), CancellationToken.None);
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.ThrottleConfigUpdated, resourceType: "TenantThrottleConfig"), CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var results = await _logger.QueryAsync(new SuppressionAuditQuery
|
||||
{
|
||||
TenantId = "tenant1",
|
||||
ResourceType = "QuietHourCalendar"
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Single(results);
|
||||
@@ -131,15 +131,15 @@ public class SuppressionAuditLoggerTests
|
||||
public async Task QueryAsync_FiltersByResourceId()
|
||||
{
|
||||
// Arrange
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated, resourceId: "cal-123"));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarUpdated, resourceId: "cal-456"));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated, resourceId: "cal-123"), CancellationToken.None);
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarUpdated, resourceId: "cal-456"), CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var results = await _logger.QueryAsync(new SuppressionAuditQuery
|
||||
{
|
||||
TenantId = "tenant1",
|
||||
ResourceId = "cal-123"
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Single(results);
|
||||
@@ -153,7 +153,7 @@ public class SuppressionAuditLoggerTests
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated, now.AddMinutes(-i)));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated, now.AddMinutes(-i)), CancellationToken.None);
|
||||
}
|
||||
|
||||
// Act
|
||||
@@ -162,14 +162,14 @@ public class SuppressionAuditLoggerTests
|
||||
TenantId = "tenant1",
|
||||
Limit = 3,
|
||||
Offset = 0
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
var secondPage = await _logger.QueryAsync(new SuppressionAuditQuery
|
||||
{
|
||||
TenantId = "tenant1",
|
||||
Limit = 3,
|
||||
Offset = 3
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, firstPage.Count);
|
||||
@@ -182,12 +182,12 @@ public class SuppressionAuditLoggerTests
|
||||
{
|
||||
// Arrange
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated, now.AddHours(-2)));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarUpdated, now.AddHours(-1)));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarDeleted, now));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated, now.AddHours(-2)), CancellationToken.None);
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarUpdated, now.AddHours(-1)), CancellationToken.None);
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarDeleted, now), CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var results = await _logger.QueryAsync(new SuppressionAuditQuery { TenantId = "tenant1" });
|
||||
var results = await _logger.QueryAsync(new SuppressionAuditQuery { TenantId = "tenant1" }, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, results.Count);
|
||||
@@ -207,11 +207,11 @@ public class SuppressionAuditLoggerTests
|
||||
// Act - Add more entries than the limit
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
await logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated));
|
||||
await logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated), CancellationToken.None);
|
||||
}
|
||||
|
||||
// Assert
|
||||
var results = await logger.QueryAsync(new SuppressionAuditQuery { TenantId = "tenant1" });
|
||||
var results = await logger.QueryAsync(new SuppressionAuditQuery { TenantId = "tenant1" }, CancellationToken.None);
|
||||
Assert.Equal(5, results.Count);
|
||||
}
|
||||
|
||||
@@ -219,13 +219,13 @@ public class SuppressionAuditLoggerTests
|
||||
public async Task LogAsync_IsolatesTenantsCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated));
|
||||
await _logger.LogAsync(CreateEntry("tenant2", SuppressionAuditAction.CalendarUpdated));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarDeleted));
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarCreated), CancellationToken.None);
|
||||
await _logger.LogAsync(CreateEntry("tenant2", SuppressionAuditAction.CalendarUpdated), CancellationToken.None);
|
||||
await _logger.LogAsync(CreateEntry("tenant1", SuppressionAuditAction.CalendarDeleted), CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var tenant1Results = await _logger.QueryAsync(new SuppressionAuditQuery { TenantId = "tenant1" });
|
||||
var tenant2Results = await _logger.QueryAsync(new SuppressionAuditQuery { TenantId = "tenant2" });
|
||||
var tenant1Results = await _logger.QueryAsync(new SuppressionAuditQuery { TenantId = "tenant1" }, CancellationToken.None);
|
||||
var tenant2Results = await _logger.QueryAsync(new SuppressionAuditQuery { TenantId = "tenant2" }, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, tenant1Results.Count);
|
||||
|
||||
@@ -35,7 +35,7 @@ public class ThrottleConfigServiceTests
|
||||
public async Task GetEffectiveConfigAsync_ReturnsGlobalDefaultsWhenNoTenantConfig()
|
||||
{
|
||||
// Act
|
||||
var config = await _service.GetEffectiveConfigAsync("tenant1", "vulnerability.found");
|
||||
var config = await _service.GetEffectiveConfigAsync("tenant1", "vulnerability.found", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(config.Enabled);
|
||||
@@ -56,7 +56,7 @@ public class ThrottleConfigServiceTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var config = await _service.SetTenantConfigAsync("tenant1", update, "admin");
|
||||
var config = await _service.SetTenantConfigAsync("tenant1", update, "admin", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("tenant1", config.TenantId);
|
||||
@@ -73,7 +73,7 @@ public class ThrottleConfigServiceTests
|
||||
var update = new TenantThrottleConfigUpdate { DefaultMaxEvents = 50 };
|
||||
|
||||
// Act
|
||||
await _service.SetTenantConfigAsync("tenant1", update, "admin");
|
||||
await _service.SetTenantConfigAsync("tenant1", update, "admin", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
_auditLogger.Verify(a => a.LogAsync(
|
||||
@@ -92,10 +92,10 @@ public class ThrottleConfigServiceTests
|
||||
{
|
||||
DefaultWindow = TimeSpan.FromMinutes(15),
|
||||
DefaultMaxEvents = 25
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var config = await _service.GetEffectiveConfigAsync("tenant1", "event.test");
|
||||
var config = await _service.GetEffectiveConfigAsync("tenant1", "event.test", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(TimeSpan.FromMinutes(15), config.Window);
|
||||
@@ -114,7 +114,7 @@ public class ThrottleConfigServiceTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var config = await _service.SetEventKindConfigAsync("tenant1", "critical.*", update, "admin");
|
||||
var config = await _service.SetEventKindConfigAsync("tenant1", "critical.*", update, "admin", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("tenant1", config.TenantId);
|
||||
@@ -131,17 +131,17 @@ public class ThrottleConfigServiceTests
|
||||
{
|
||||
DefaultWindow = TimeSpan.FromMinutes(10),
|
||||
DefaultMaxEvents = 20
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
await _service.SetEventKindConfigAsync("tenant1", "critical.*", new EventKindThrottleConfigUpdate
|
||||
{
|
||||
Window = TimeSpan.FromMinutes(1),
|
||||
MaxEvents = 100
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var criticalConfig = await _service.GetEffectiveConfigAsync("tenant1", "critical.security.breach");
|
||||
var normalConfig = await _service.GetEffectiveConfigAsync("tenant1", "info.scan.complete");
|
||||
var criticalConfig = await _service.GetEffectiveConfigAsync("tenant1", "critical.security.breach", CancellationToken.None);
|
||||
var normalConfig = await _service.GetEffectiveConfigAsync("tenant1", "info.scan.complete", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("event_kind", criticalConfig.Source);
|
||||
@@ -162,17 +162,17 @@ public class ThrottleConfigServiceTests
|
||||
{
|
||||
MaxEvents = 10,
|
||||
Priority = 100
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
await _service.SetEventKindConfigAsync("tenant1", "vulnerability.critical.*", new EventKindThrottleConfigUpdate
|
||||
{
|
||||
MaxEvents = 5,
|
||||
Priority = 50 // Higher priority (lower number)
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var specificConfig = await _service.GetEffectiveConfigAsync("tenant1", "vulnerability.critical.cve123");
|
||||
var generalConfig = await _service.GetEffectiveConfigAsync("tenant1", "vulnerability.low.cve456");
|
||||
var specificConfig = await _service.GetEffectiveConfigAsync("tenant1", "vulnerability.critical.cve123", CancellationToken.None);
|
||||
var generalConfig = await _service.GetEffectiveConfigAsync("tenant1", "vulnerability.low.cve456", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(5, specificConfig.MaxEvents);
|
||||
@@ -190,15 +190,15 @@ public class ThrottleConfigServiceTests
|
||||
{
|
||||
Enabled = true,
|
||||
DefaultMaxEvents = 20
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
await _service.SetEventKindConfigAsync("tenant1", "info.*", new EventKindThrottleConfigUpdate
|
||||
{
|
||||
Enabled = false
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var config = await _service.GetEffectiveConfigAsync("tenant1", "info.log");
|
||||
var config = await _service.GetEffectiveConfigAsync("tenant1", "info.log", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(config.Enabled);
|
||||
@@ -209,12 +209,12 @@ public class ThrottleConfigServiceTests
|
||||
public async Task ListEventKindConfigsAsync_ReturnsAllConfigsForTenant()
|
||||
{
|
||||
// Arrange
|
||||
await _service.SetEventKindConfigAsync("tenant1", "critical.*", new EventKindThrottleConfigUpdate { MaxEvents = 5, Priority = 10 }, "admin");
|
||||
await _service.SetEventKindConfigAsync("tenant1", "info.*", new EventKindThrottleConfigUpdate { MaxEvents = 100, Priority = 100 }, "admin");
|
||||
await _service.SetEventKindConfigAsync("tenant2", "other.*", new EventKindThrottleConfigUpdate { MaxEvents = 50 }, "admin");
|
||||
await _service.SetEventKindConfigAsync("tenant1", "critical.*", new EventKindThrottleConfigUpdate { MaxEvents = 5, Priority = 10 }, "admin", CancellationToken.None);
|
||||
await _service.SetEventKindConfigAsync("tenant1", "info.*", new EventKindThrottleConfigUpdate { MaxEvents = 100, Priority = 100 }, "admin", CancellationToken.None);
|
||||
await _service.SetEventKindConfigAsync("tenant2", "other.*", new EventKindThrottleConfigUpdate { MaxEvents = 50 }, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var configs = await _service.ListEventKindConfigsAsync("tenant1");
|
||||
var configs = await _service.ListEventKindConfigsAsync("tenant1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, configs.Count);
|
||||
@@ -226,14 +226,14 @@ public class ThrottleConfigServiceTests
|
||||
public async Task RemoveEventKindConfigAsync_RemovesConfig()
|
||||
{
|
||||
// Arrange
|
||||
await _service.SetEventKindConfigAsync("tenant1", "test.*", new EventKindThrottleConfigUpdate { MaxEvents = 5 }, "admin");
|
||||
await _service.SetEventKindConfigAsync("tenant1", "test.*", new EventKindThrottleConfigUpdate { MaxEvents = 5 }, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var removed = await _service.RemoveEventKindConfigAsync("tenant1", "test.*", "admin");
|
||||
var removed = await _service.RemoveEventKindConfigAsync("tenant1", "test.*", "admin", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(removed);
|
||||
var configs = await _service.ListEventKindConfigsAsync("tenant1");
|
||||
var configs = await _service.ListEventKindConfigsAsync("tenant1", CancellationToken.None);
|
||||
Assert.Empty(configs);
|
||||
}
|
||||
|
||||
@@ -241,10 +241,10 @@ public class ThrottleConfigServiceTests
|
||||
public async Task RemoveEventKindConfigAsync_LogsAuditEntry()
|
||||
{
|
||||
// Arrange
|
||||
await _service.SetEventKindConfigAsync("tenant1", "test.*", new EventKindThrottleConfigUpdate { MaxEvents = 5 }, "admin");
|
||||
await _service.SetEventKindConfigAsync("tenant1", "test.*", new EventKindThrottleConfigUpdate { MaxEvents = 5 }, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
await _service.RemoveEventKindConfigAsync("tenant1", "test.*", "admin");
|
||||
await _service.RemoveEventKindConfigAsync("tenant1", "test.*", "admin", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
_auditLogger.Verify(a => a.LogAsync(
|
||||
@@ -258,7 +258,7 @@ public class ThrottleConfigServiceTests
|
||||
public async Task GetTenantConfigAsync_ReturnsNullWhenNotSet()
|
||||
{
|
||||
// Act
|
||||
var config = await _service.GetTenantConfigAsync("nonexistent");
|
||||
var config = await _service.GetTenantConfigAsync("nonexistent", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Null(config);
|
||||
@@ -268,10 +268,10 @@ public class ThrottleConfigServiceTests
|
||||
public async Task GetTenantConfigAsync_ReturnsConfigWhenSet()
|
||||
{
|
||||
// Arrange
|
||||
await _service.SetTenantConfigAsync("tenant1", new TenantThrottleConfigUpdate { DefaultMaxEvents = 50 }, "admin");
|
||||
await _service.SetTenantConfigAsync("tenant1", new TenantThrottleConfigUpdate { DefaultMaxEvents = 50 }, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var config = await _service.GetTenantConfigAsync("tenant1");
|
||||
var config = await _service.GetTenantConfigAsync("tenant1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(config);
|
||||
@@ -282,10 +282,10 @@ public class ThrottleConfigServiceTests
|
||||
public async Task SetTenantConfigAsync_UpdatesExistingConfig()
|
||||
{
|
||||
// Arrange
|
||||
await _service.SetTenantConfigAsync("tenant1", new TenantThrottleConfigUpdate { DefaultMaxEvents = 10 }, "admin1");
|
||||
await _service.SetTenantConfigAsync("tenant1", new TenantThrottleConfigUpdate { DefaultMaxEvents = 10 }, "admin1", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var updated = await _service.SetTenantConfigAsync("tenant1", new TenantThrottleConfigUpdate { DefaultMaxEvents = 20 }, "admin2");
|
||||
var updated = await _service.SetTenantConfigAsync("tenant1", new TenantThrottleConfigUpdate { DefaultMaxEvents = 20 }, "admin2", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(20, updated.DefaultMaxEvents);
|
||||
@@ -300,10 +300,10 @@ public class ThrottleConfigServiceTests
|
||||
{
|
||||
BurstAllowance = 5,
|
||||
CooldownPeriod = TimeSpan.FromMinutes(10)
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var config = await _service.GetEffectiveConfigAsync("tenant1", "event.test");
|
||||
var config = await _service.GetEffectiveConfigAsync("tenant1", "event.test", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(5, config.BurstAllowance);
|
||||
@@ -318,10 +318,10 @@ public class ThrottleConfigServiceTests
|
||||
{
|
||||
MaxEvents = 1000,
|
||||
Priority = 1000 // Very low priority
|
||||
}, "admin");
|
||||
}, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var config = await _service.GetEffectiveConfigAsync("tenant1", "any.event.kind.here");
|
||||
var config = await _service.GetEffectiveConfigAsync("tenant1", "any.event.kind.here", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1000, config.MaxEvents);
|
||||
|
||||
@@ -50,7 +50,7 @@ public sealed class DigestGeneratorTests
|
||||
var query = DigestQuery.LastHours(24, _timeProvider.GetUtcNow());
|
||||
|
||||
// Act
|
||||
var result = await _generator.GenerateAsync("tenant-1", query);
|
||||
var result = await _generator.GenerateAsync("tenant-1", query, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
@@ -65,15 +65,14 @@ public sealed class DigestGeneratorTests
|
||||
public async Task GenerateAsync_WithIncidents_ReturnsSummary()
|
||||
{
|
||||
// Arrange
|
||||
var incident = await _incidentManager.GetOrCreateIncidentAsync(
|
||||
"tenant-1", "vuln:critical:pkg-foo", "vulnerability.detected", "Critical vulnerability in pkg-foo");
|
||||
await _incidentManager.RecordEventAsync("tenant-1", incident.IncidentId, "evt-1");
|
||||
await _incidentManager.RecordEventAsync("tenant-1", incident.IncidentId, "evt-2");
|
||||
var incident = await _incidentManager.GetOrCreateIncidentAsync("tenant-1", "vuln:critical:pkg-foo", "vulnerability.detected", "Critical vulnerability in pkg-foo", CancellationToken.None);
|
||||
await _incidentManager.RecordEventAsync("tenant-1", incident.IncidentId, "evt-1", CancellationToken.None);
|
||||
await _incidentManager.RecordEventAsync("tenant-1", incident.IncidentId, "evt-2", CancellationToken.None);
|
||||
|
||||
var query = DigestQuery.LastHours(24, _timeProvider.GetUtcNow());
|
||||
|
||||
// Act
|
||||
var result = await _generator.GenerateAsync("tenant-1", query);
|
||||
var result = await _generator.GenerateAsync("tenant-1", query, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Single(result.Incidents);
|
||||
@@ -87,22 +86,19 @@ public sealed class DigestGeneratorTests
|
||||
public async Task GenerateAsync_MultipleIncidents_GroupsByEventKind()
|
||||
{
|
||||
// Arrange
|
||||
var inc1 = await _incidentManager.GetOrCreateIncidentAsync(
|
||||
"tenant-1", "key1", "vulnerability.detected", "Vuln 1");
|
||||
await _incidentManager.RecordEventAsync("tenant-1", inc1.IncidentId, "evt-1");
|
||||
var inc1 = await _incidentManager.GetOrCreateIncidentAsync("tenant-1", "key1", "vulnerability.detected", "Vuln 1", CancellationToken.None);
|
||||
await _incidentManager.RecordEventAsync("tenant-1", inc1.IncidentId, "evt-1", CancellationToken.None);
|
||||
|
||||
var inc2 = await _incidentManager.GetOrCreateIncidentAsync(
|
||||
"tenant-1", "key2", "vulnerability.detected", "Vuln 2");
|
||||
await _incidentManager.RecordEventAsync("tenant-1", inc2.IncidentId, "evt-2");
|
||||
var inc2 = await _incidentManager.GetOrCreateIncidentAsync("tenant-1", "key2", "vulnerability.detected", "Vuln 2", CancellationToken.None);
|
||||
await _incidentManager.RecordEventAsync("tenant-1", inc2.IncidentId, "evt-2", CancellationToken.None);
|
||||
|
||||
var inc3 = await _incidentManager.GetOrCreateIncidentAsync(
|
||||
"tenant-1", "key3", "pack.approval.required", "Approval needed");
|
||||
await _incidentManager.RecordEventAsync("tenant-1", inc3.IncidentId, "evt-3");
|
||||
var inc3 = await _incidentManager.GetOrCreateIncidentAsync("tenant-1", "key3", "pack.approval.required", "Approval needed", CancellationToken.None);
|
||||
await _incidentManager.RecordEventAsync("tenant-1", inc3.IncidentId, "evt-3", CancellationToken.None);
|
||||
|
||||
var query = DigestQuery.LastHours(24, _timeProvider.GetUtcNow());
|
||||
|
||||
// Act
|
||||
var result = await _generator.GenerateAsync("tenant-1", query);
|
||||
var result = await _generator.GenerateAsync("tenant-1", query, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, result.Incidents.Count);
|
||||
@@ -117,14 +113,13 @@ public sealed class DigestGeneratorTests
|
||||
public async Task GenerateAsync_RendersContent()
|
||||
{
|
||||
// Arrange
|
||||
var incident = await _incidentManager.GetOrCreateIncidentAsync(
|
||||
"tenant-1", "key", "vulnerability.detected", "Critical issue");
|
||||
await _incidentManager.RecordEventAsync("tenant-1", incident.IncidentId, "evt-1");
|
||||
var incident = await _incidentManager.GetOrCreateIncidentAsync("tenant-1", "key", "vulnerability.detected", "Critical issue", CancellationToken.None);
|
||||
await _incidentManager.RecordEventAsync("tenant-1", incident.IncidentId, "evt-1", CancellationToken.None);
|
||||
|
||||
var query = DigestQuery.LastHours(24, _timeProvider.GetUtcNow());
|
||||
|
||||
// Act
|
||||
var result = await _generator.GenerateAsync("tenant-1", query);
|
||||
var result = await _generator.GenerateAsync("tenant-1", query, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result.Content);
|
||||
@@ -145,9 +140,8 @@ public sealed class DigestGeneratorTests
|
||||
// Arrange
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
var inc = await _incidentManager.GetOrCreateIncidentAsync(
|
||||
"tenant-1", $"key-{i}", "test.event", $"Test incident {i}");
|
||||
await _incidentManager.RecordEventAsync("tenant-1", inc.IncidentId, $"evt-{i}");
|
||||
var inc = await _incidentManager.GetOrCreateIncidentAsync("tenant-1", $"key-{i}", "test.event", $"Test incident {i}", CancellationToken.None);
|
||||
await _incidentManager.RecordEventAsync("tenant-1", inc.IncidentId, $"evt-{i}", CancellationToken.None);
|
||||
}
|
||||
|
||||
var query = new DigestQuery
|
||||
@@ -158,7 +152,7 @@ public sealed class DigestGeneratorTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _generator.GenerateAsync("tenant-1", query);
|
||||
var result = await _generator.GenerateAsync("tenant-1", query, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(5, result.Incidents.Count);
|
||||
@@ -170,14 +164,12 @@ public sealed class DigestGeneratorTests
|
||||
public async Task GenerateAsync_FiltersResolvedIncidents()
|
||||
{
|
||||
// Arrange
|
||||
var openInc = await _incidentManager.GetOrCreateIncidentAsync(
|
||||
"tenant-1", "key-open", "test.event", "Open incident");
|
||||
await _incidentManager.RecordEventAsync("tenant-1", openInc.IncidentId, "evt-1");
|
||||
var openInc = await _incidentManager.GetOrCreateIncidentAsync("tenant-1", "key-open", "test.event", "Open incident", CancellationToken.None);
|
||||
await _incidentManager.RecordEventAsync("tenant-1", openInc.IncidentId, "evt-1", CancellationToken.None);
|
||||
|
||||
var resolvedInc = await _incidentManager.GetOrCreateIncidentAsync(
|
||||
"tenant-1", "key-resolved", "test.event", "Resolved incident");
|
||||
await _incidentManager.RecordEventAsync("tenant-1", resolvedInc.IncidentId, "evt-2");
|
||||
await _incidentManager.ResolveAsync("tenant-1", resolvedInc.IncidentId, "system", "Auto-resolved");
|
||||
var resolvedInc = await _incidentManager.GetOrCreateIncidentAsync("tenant-1", "key-resolved", "test.event", "Resolved incident", CancellationToken.None);
|
||||
await _incidentManager.RecordEventAsync("tenant-1", resolvedInc.IncidentId, "evt-2", CancellationToken.None);
|
||||
await _incidentManager.ResolveAsync("tenant-1", resolvedInc.IncidentId, "system", "Auto-resolved", CancellationToken.None);
|
||||
|
||||
var queryExcludeResolved = new DigestQuery
|
||||
{
|
||||
@@ -194,8 +186,8 @@ public sealed class DigestGeneratorTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var resultExclude = await _generator.GenerateAsync("tenant-1", queryExcludeResolved);
|
||||
var resultInclude = await _generator.GenerateAsync("tenant-1", queryIncludeResolved);
|
||||
var resultExclude = await _generator.GenerateAsync("tenant-1", queryExcludeResolved, CancellationToken.None);
|
||||
var resultInclude = await _generator.GenerateAsync("tenant-1", queryIncludeResolved, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Single(resultExclude.Incidents);
|
||||
@@ -208,13 +200,11 @@ public sealed class DigestGeneratorTests
|
||||
public async Task GenerateAsync_FiltersEventKinds()
|
||||
{
|
||||
// Arrange
|
||||
var vulnInc = await _incidentManager.GetOrCreateIncidentAsync(
|
||||
"tenant-1", "key-vuln", "vulnerability.detected", "Vulnerability");
|
||||
await _incidentManager.RecordEventAsync("tenant-1", vulnInc.IncidentId, "evt-1");
|
||||
var vulnInc = await _incidentManager.GetOrCreateIncidentAsync("tenant-1", "key-vuln", "vulnerability.detected", "Vulnerability", CancellationToken.None);
|
||||
await _incidentManager.RecordEventAsync("tenant-1", vulnInc.IncidentId, "evt-1", CancellationToken.None);
|
||||
|
||||
var approvalInc = await _incidentManager.GetOrCreateIncidentAsync(
|
||||
"tenant-1", "key-approval", "pack.approval.required", "Approval");
|
||||
await _incidentManager.RecordEventAsync("tenant-1", approvalInc.IncidentId, "evt-2");
|
||||
var approvalInc = await _incidentManager.GetOrCreateIncidentAsync("tenant-1", "key-approval", "pack.approval.required", "Approval", CancellationToken.None);
|
||||
await _incidentManager.RecordEventAsync("tenant-1", approvalInc.IncidentId, "evt-2", CancellationToken.None);
|
||||
|
||||
var query = new DigestQuery
|
||||
{
|
||||
@@ -224,7 +214,7 @@ public sealed class DigestGeneratorTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _generator.GenerateAsync("tenant-1", query);
|
||||
var result = await _generator.GenerateAsync("tenant-1", query, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Single(result.Incidents);
|
||||
@@ -235,14 +225,13 @@ public sealed class DigestGeneratorTests
|
||||
public async Task PreviewAsync_SetsIsPreviewFlag()
|
||||
{
|
||||
// Arrange
|
||||
var incident = await _incidentManager.GetOrCreateIncidentAsync(
|
||||
"tenant-1", "key", "test.event", "Test");
|
||||
await _incidentManager.RecordEventAsync("tenant-1", incident.IncidentId, "evt-1");
|
||||
var incident = await _incidentManager.GetOrCreateIncidentAsync("tenant-1", "key", "test.event", "Test", CancellationToken.None);
|
||||
await _incidentManager.RecordEventAsync("tenant-1", incident.IncidentId, "evt-1", CancellationToken.None);
|
||||
|
||||
var query = DigestQuery.LastHours(24, _timeProvider.GetUtcNow());
|
||||
|
||||
// Act
|
||||
var result = await _generator.PreviewAsync("tenant-1", query);
|
||||
var result = await _generator.PreviewAsync("tenant-1", query, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsPreview);
|
||||
|
||||
@@ -24,7 +24,7 @@ public class InMemoryDigestSchedulerTests
|
||||
var schedule = CreateTestSchedule("schedule-1");
|
||||
|
||||
// Act
|
||||
var result = await _scheduler.UpsertScheduleAsync(schedule);
|
||||
var result = await _scheduler.UpsertScheduleAsync(schedule, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
@@ -37,12 +37,12 @@ public class InMemoryDigestSchedulerTests
|
||||
{
|
||||
// Arrange
|
||||
var schedule = CreateTestSchedule("schedule-1");
|
||||
await _scheduler.UpsertScheduleAsync(schedule);
|
||||
await _scheduler.UpsertScheduleAsync(schedule, CancellationToken.None);
|
||||
|
||||
var updated = schedule with { Name = "Updated Name" };
|
||||
|
||||
// Act
|
||||
var result = await _scheduler.UpsertScheduleAsync(updated);
|
||||
var result = await _scheduler.UpsertScheduleAsync(updated, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Updated Name", result.Name);
|
||||
@@ -53,10 +53,10 @@ public class InMemoryDigestSchedulerTests
|
||||
{
|
||||
// Arrange
|
||||
var schedule = CreateTestSchedule("schedule-1");
|
||||
await _scheduler.UpsertScheduleAsync(schedule);
|
||||
await _scheduler.UpsertScheduleAsync(schedule, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _scheduler.GetScheduleAsync("tenant1", "schedule-1");
|
||||
var result = await _scheduler.GetScheduleAsync("tenant1", "schedule-1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
@@ -67,7 +67,7 @@ public class InMemoryDigestSchedulerTests
|
||||
public async Task GetScheduleAsync_ReturnsNullForUnknown()
|
||||
{
|
||||
// Act
|
||||
var result = await _scheduler.GetScheduleAsync("tenant1", "unknown");
|
||||
var result = await _scheduler.GetScheduleAsync("tenant1", "unknown", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
@@ -77,12 +77,12 @@ public class InMemoryDigestSchedulerTests
|
||||
public async Task GetSchedulesAsync_ReturnsTenantSchedules()
|
||||
{
|
||||
// Arrange
|
||||
await _scheduler.UpsertScheduleAsync(CreateTestSchedule("schedule-1", "tenant1"));
|
||||
await _scheduler.UpsertScheduleAsync(CreateTestSchedule("schedule-2", "tenant1"));
|
||||
await _scheduler.UpsertScheduleAsync(CreateTestSchedule("schedule-3", "tenant2"));
|
||||
await _scheduler.UpsertScheduleAsync(CreateTestSchedule("schedule-1", "tenant1"), CancellationToken.None);
|
||||
await _scheduler.UpsertScheduleAsync(CreateTestSchedule("schedule-2", "tenant1"), CancellationToken.None);
|
||||
await _scheduler.UpsertScheduleAsync(CreateTestSchedule("schedule-3", "tenant2"), CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _scheduler.GetSchedulesAsync("tenant1");
|
||||
var result = await _scheduler.GetSchedulesAsync("tenant1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, result.Count);
|
||||
@@ -93,14 +93,14 @@ public class InMemoryDigestSchedulerTests
|
||||
public async Task DeleteScheduleAsync_RemovesSchedule()
|
||||
{
|
||||
// Arrange
|
||||
await _scheduler.UpsertScheduleAsync(CreateTestSchedule("schedule-1"));
|
||||
await _scheduler.UpsertScheduleAsync(CreateTestSchedule("schedule-1"), CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var deleted = await _scheduler.DeleteScheduleAsync("tenant1", "schedule-1");
|
||||
var deleted = await _scheduler.DeleteScheduleAsync("tenant1", "schedule-1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(deleted);
|
||||
var result = await _scheduler.GetScheduleAsync("tenant1", "schedule-1");
|
||||
var result = await _scheduler.GetScheduleAsync("tenant1", "schedule-1", CancellationToken.None);
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ public class InMemoryDigestSchedulerTests
|
||||
public async Task DeleteScheduleAsync_ReturnsFalseForUnknown()
|
||||
{
|
||||
// Act
|
||||
var deleted = await _scheduler.DeleteScheduleAsync("tenant1", "unknown");
|
||||
var deleted = await _scheduler.DeleteScheduleAsync("tenant1", "unknown", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(deleted);
|
||||
@@ -122,13 +122,13 @@ public class InMemoryDigestSchedulerTests
|
||||
{
|
||||
CronExpression = "0 * * * * *" // Every minute
|
||||
};
|
||||
await _scheduler.UpsertScheduleAsync(schedule);
|
||||
await _scheduler.UpsertScheduleAsync(schedule, CancellationToken.None);
|
||||
|
||||
// Advance time past next run
|
||||
_timeProvider.Advance(TimeSpan.FromMinutes(2));
|
||||
|
||||
// Act
|
||||
var dueSchedules = await _scheduler.GetDueSchedulesAsync(_timeProvider.GetUtcNow());
|
||||
var dueSchedules = await _scheduler.GetDueSchedulesAsync(_timeProvider.GetUtcNow(), CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Single(dueSchedules);
|
||||
@@ -144,12 +144,12 @@ public class InMemoryDigestSchedulerTests
|
||||
Enabled = false,
|
||||
CronExpression = "0 * * * * *"
|
||||
};
|
||||
await _scheduler.UpsertScheduleAsync(schedule);
|
||||
await _scheduler.UpsertScheduleAsync(schedule, CancellationToken.None);
|
||||
|
||||
_timeProvider.Advance(TimeSpan.FromMinutes(2));
|
||||
|
||||
// Act
|
||||
var dueSchedules = await _scheduler.GetDueSchedulesAsync(_timeProvider.GetUtcNow());
|
||||
var dueSchedules = await _scheduler.GetDueSchedulesAsync(_timeProvider.GetUtcNow(), CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(dueSchedules);
|
||||
@@ -163,15 +163,15 @@ public class InMemoryDigestSchedulerTests
|
||||
{
|
||||
CronExpression = "0 0 * * * *" // Every hour
|
||||
};
|
||||
await _scheduler.UpsertScheduleAsync(schedule);
|
||||
await _scheduler.UpsertScheduleAsync(schedule, CancellationToken.None);
|
||||
|
||||
var runTime = _timeProvider.GetUtcNow();
|
||||
|
||||
// Act
|
||||
await _scheduler.UpdateLastRunAsync("tenant1", "schedule-1", runTime);
|
||||
await _scheduler.UpdateLastRunAsync("tenant1", "schedule-1", runTime, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var updated = await _scheduler.GetScheduleAsync("tenant1", "schedule-1");
|
||||
var updated = await _scheduler.GetScheduleAsync("tenant1", "schedule-1", CancellationToken.None);
|
||||
Assert.NotNull(updated);
|
||||
Assert.Equal(runTime, updated.LastRunAt);
|
||||
Assert.NotNull(updated.NextRunAt);
|
||||
@@ -189,7 +189,7 @@ public class InMemoryDigestSchedulerTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _scheduler.UpsertScheduleAsync(schedule);
|
||||
var result = await _scheduler.UpsertScheduleAsync(schedule, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result.NextRunAt);
|
||||
@@ -205,7 +205,7 @@ public class InMemoryDigestSchedulerTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _scheduler.UpsertScheduleAsync(schedule);
|
||||
var result = await _scheduler.UpsertScheduleAsync(schedule, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result.NextRunAt);
|
||||
@@ -215,12 +215,12 @@ public class InMemoryDigestSchedulerTests
|
||||
public async Task GetSchedulesAsync_OrdersByName()
|
||||
{
|
||||
// Arrange
|
||||
await _scheduler.UpsertScheduleAsync(CreateTestSchedule("schedule-c") with { Name = "Charlie" });
|
||||
await _scheduler.UpsertScheduleAsync(CreateTestSchedule("schedule-a") with { Name = "Alpha" });
|
||||
await _scheduler.UpsertScheduleAsync(CreateTestSchedule("schedule-b") with { Name = "Bravo" });
|
||||
await _scheduler.UpsertScheduleAsync(CreateTestSchedule("schedule-c") with { Name = "Charlie" }, CancellationToken.None);
|
||||
await _scheduler.UpsertScheduleAsync(CreateTestSchedule("schedule-a") with { Name = "Alpha" }, CancellationToken.None);
|
||||
await _scheduler.UpsertScheduleAsync(CreateTestSchedule("schedule-b") with { Name = "Bravo" }, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _scheduler.GetSchedulesAsync("tenant1");
|
||||
var result = await _scheduler.GetSchedulesAsync("tenant1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, result.Count);
|
||||
|
||||
@@ -35,7 +35,7 @@ public sealed class SimpleTemplateRendererTests
|
||||
actor: "admin@example.com",
|
||||
version: "1");
|
||||
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
Assert.Contains("Hello admin@example.com", result.Body);
|
||||
Assert.Contains("event policy.violation occurred", result.Body);
|
||||
@@ -67,7 +67,7 @@ public sealed class SimpleTemplateRendererTests
|
||||
payload: payload,
|
||||
version: "1");
|
||||
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
Assert.Contains("Image: registry.local/api:v1.0", result.Body);
|
||||
Assert.Contains("Severity: critical", result.Body);
|
||||
@@ -101,7 +101,7 @@ public sealed class SimpleTemplateRendererTests
|
||||
payload: payload,
|
||||
version: "1");
|
||||
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
Assert.Contains("Package: lodash v4.17.21", result.Body);
|
||||
}
|
||||
@@ -131,7 +131,7 @@ public sealed class SimpleTemplateRendererTests
|
||||
payload: payload,
|
||||
version: "1");
|
||||
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
Assert.Contains("[REDACTED]", result.Body);
|
||||
Assert.Contains("User: testuser", result.Body);
|
||||
@@ -157,7 +157,7 @@ public sealed class SimpleTemplateRendererTests
|
||||
payload: new JsonObject(),
|
||||
version: "1");
|
||||
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
Assert.Equal("Value: -end", result.Body);
|
||||
}
|
||||
@@ -186,7 +186,7 @@ public sealed class SimpleTemplateRendererTests
|
||||
payload: payload,
|
||||
version: "1");
|
||||
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
Assert.Contains("alpha", result.Body);
|
||||
Assert.Contains("beta", result.Body);
|
||||
@@ -213,7 +213,7 @@ public sealed class SimpleTemplateRendererTests
|
||||
payload: new JsonObject(),
|
||||
version: "1");
|
||||
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
Assert.Equal("Alert: critical.alert", result.Subject);
|
||||
}
|
||||
@@ -237,8 +237,8 @@ public sealed class SimpleTemplateRendererTests
|
||||
payload: new JsonObject(),
|
||||
version: "1");
|
||||
|
||||
var result1 = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result2 = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result1 = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
var result2 = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
Assert.Equal(result1.BodyHash, result2.BodyHash);
|
||||
Assert.Equal(64, result1.BodyHash.Length); // SHA256 hex
|
||||
@@ -264,7 +264,7 @@ public sealed class SimpleTemplateRendererTests
|
||||
payload: new JsonObject(),
|
||||
version: "1");
|
||||
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
Assert.Equal(NotifyDeliveryFormat.Markdown, result.Format);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public sealed class WebhookChannelDispatcherTests
|
||||
var content = CreateContent("Test message");
|
||||
var delivery = CreateDelivery();
|
||||
|
||||
var result = await dispatcher.DispatchAsync(channel, content, delivery);
|
||||
var result = await dispatcher.DispatchAsync(channel, content, delivery, CancellationToken.None);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.Equal(NotifyDeliveryStatus.Delivered, result.Status);
|
||||
@@ -49,7 +49,7 @@ public sealed class WebhookChannelDispatcherTests
|
||||
var content = CreateContent("Test message");
|
||||
var delivery = CreateDelivery();
|
||||
|
||||
var result = await dispatcher.DispatchAsync(channel, content, delivery);
|
||||
var result = await dispatcher.DispatchAsync(channel, content, delivery, CancellationToken.None);
|
||||
|
||||
Assert.False(result.Success);
|
||||
Assert.Equal(NotifyDeliveryStatus.Failed, result.Status);
|
||||
@@ -67,7 +67,7 @@ public sealed class WebhookChannelDispatcherTests
|
||||
var content = CreateContent("Test message");
|
||||
var delivery = CreateDelivery();
|
||||
|
||||
var result = await dispatcher.DispatchAsync(channel, content, delivery);
|
||||
var result = await dispatcher.DispatchAsync(channel, content, delivery, CancellationToken.None);
|
||||
|
||||
Assert.False(result.Success);
|
||||
Assert.Contains("Invalid webhook endpoint", result.ErrorMessage);
|
||||
@@ -84,7 +84,7 @@ public sealed class WebhookChannelDispatcherTests
|
||||
var content = CreateContent("Test message");
|
||||
var delivery = CreateDelivery();
|
||||
|
||||
var result = await dispatcher.DispatchAsync(channel, content, delivery);
|
||||
var result = await dispatcher.DispatchAsync(channel, content, delivery, CancellationToken.None);
|
||||
|
||||
Assert.False(result.Success);
|
||||
Assert.Equal(NotifyDeliveryStatus.Failed, result.Status);
|
||||
@@ -102,7 +102,7 @@ public sealed class WebhookChannelDispatcherTests
|
||||
var content = CreateContent("Test message");
|
||||
var delivery = CreateDelivery();
|
||||
|
||||
var result = await dispatcher.DispatchAsync(channel, content, delivery);
|
||||
var result = await dispatcher.DispatchAsync(channel, content, delivery, CancellationToken.None);
|
||||
|
||||
Assert.False(result.Success);
|
||||
Assert.True(result.IsRetryable);
|
||||
@@ -120,7 +120,7 @@ public sealed class WebhookChannelDispatcherTests
|
||||
var content = CreateContent("Test message");
|
||||
var delivery = CreateDelivery();
|
||||
|
||||
var result = await dispatcher.DispatchAsync(channel, content, delivery);
|
||||
var result = await dispatcher.DispatchAsync(channel, content, delivery, CancellationToken.None);
|
||||
|
||||
Assert.False(result.Success);
|
||||
Assert.True(result.IsRetryable);
|
||||
@@ -150,7 +150,7 @@ public sealed class WebhookChannelDispatcherTests
|
||||
var content = CreateContent("Alert notification");
|
||||
var delivery = CreateDelivery();
|
||||
|
||||
await dispatcher.DispatchAsync(channel, content, delivery);
|
||||
await dispatcher.DispatchAsync(channel, content, delivery, CancellationToken.None);
|
||||
|
||||
Assert.NotNull(capturedBody);
|
||||
Assert.Contains("\"text\":", capturedBody);
|
||||
@@ -173,7 +173,7 @@ public sealed class WebhookChannelDispatcherTests
|
||||
var content = CreateContent("Webhook content");
|
||||
var delivery = CreateDelivery();
|
||||
|
||||
await dispatcher.DispatchAsync(channel, content, delivery);
|
||||
await dispatcher.DispatchAsync(channel, content, delivery, CancellationToken.None);
|
||||
|
||||
Assert.NotNull(capturedBody);
|
||||
Assert.Contains("\"deliveryId\":", capturedBody);
|
||||
|
||||
@@ -46,11 +46,11 @@ public sealed class NotifyApiEndpointsTests : IClassFixture<WebApplicationFactor
|
||||
public async Task GetRules_ReturnsEmptyList_WhenNoRules()
|
||||
{
|
||||
// Act
|
||||
var response = await _client.GetAsync("/api/v2/notify/rules");
|
||||
var response = await _client.GetAsync("/api/v2/notify/rules", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var rules = await response.Content.ReadFromJsonAsync<List<RuleResponse>>();
|
||||
var rules = await response.Content.ReadFromJsonAsync<List<RuleResponse>>(cancellationToken: CancellationToken.None);
|
||||
Assert.NotNull(rules);
|
||||
Assert.Empty(rules);
|
||||
}
|
||||
@@ -82,11 +82,11 @@ public sealed class NotifyApiEndpointsTests : IClassFixture<WebApplicationFactor
|
||||
};
|
||||
|
||||
// Act
|
||||
var response = await _client.PostAsJsonAsync("/api/v2/notify/rules", request);
|
||||
var response = await _client.PostAsJsonAsync("/api/v2/notify/rules", request, cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
|
||||
var rule = await response.Content.ReadFromJsonAsync<RuleResponse>();
|
||||
var rule = await response.Content.ReadFromJsonAsync<RuleResponse>(cancellationToken: CancellationToken.None);
|
||||
Assert.NotNull(rule);
|
||||
Assert.Equal("rule-001", rule.RuleId);
|
||||
Assert.Equal("Test Rule", rule.Name);
|
||||
@@ -108,14 +108,14 @@ public sealed class NotifyApiEndpointsTests : IClassFixture<WebApplicationFactor
|
||||
channel: "slack:alerts",
|
||||
template: "tmpl-001")
|
||||
});
|
||||
await _ruleRepository.UpsertAsync(rule);
|
||||
await _ruleRepository.UpsertAsync(rule, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var response = await _client.GetAsync("/api/v2/notify/rules/rule-get-001");
|
||||
var response = await _client.GetAsync("/api/v2/notify/rules/rule-get-001", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var result = await response.Content.ReadFromJsonAsync<RuleResponse>();
|
||||
var result = await response.Content.ReadFromJsonAsync<RuleResponse>(cancellationToken: CancellationToken.None);
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal("rule-get-001", result.RuleId);
|
||||
}
|
||||
@@ -124,7 +124,7 @@ public sealed class NotifyApiEndpointsTests : IClassFixture<WebApplicationFactor
|
||||
public async Task GetRule_ReturnsNotFound_WhenNotExists()
|
||||
{
|
||||
// Act
|
||||
var response = await _client.GetAsync("/api/v2/notify/rules/nonexistent");
|
||||
var response = await _client.GetAsync("/api/v2/notify/rules/nonexistent", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
@@ -146,10 +146,10 @@ public sealed class NotifyApiEndpointsTests : IClassFixture<WebApplicationFactor
|
||||
channel: "slack:alerts",
|
||||
template: "tmpl-001")
|
||||
});
|
||||
await _ruleRepository.UpsertAsync(rule);
|
||||
await _ruleRepository.UpsertAsync(rule, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var response = await _client.DeleteAsync("/api/v2/notify/rules/rule-delete-001");
|
||||
var response = await _client.DeleteAsync("/api/v2/notify/rules/rule-delete-001", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
|
||||
@@ -163,11 +163,11 @@ public sealed class NotifyApiEndpointsTests : IClassFixture<WebApplicationFactor
|
||||
public async Task GetTemplates_ReturnsEmptyList_WhenNoTemplates()
|
||||
{
|
||||
// Act
|
||||
var response = await _client.GetAsync("/api/v2/notify/templates");
|
||||
var response = await _client.GetAsync("/api/v2/notify/templates", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var templates = await response.Content.ReadFromJsonAsync<List<TemplateResponse>>();
|
||||
var templates = await response.Content.ReadFromJsonAsync<List<TemplateResponse>>(cancellationToken: CancellationToken.None);
|
||||
Assert.NotNull(templates);
|
||||
}
|
||||
|
||||
@@ -182,11 +182,11 @@ public sealed class NotifyApiEndpointsTests : IClassFixture<WebApplicationFactor
|
||||
};
|
||||
|
||||
// Act
|
||||
var response = await _client.PostAsJsonAsync("/api/v2/notify/templates/preview", request);
|
||||
var response = await _client.PostAsJsonAsync("/api/v2/notify/templates/preview", request, cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var preview = await response.Content.ReadFromJsonAsync<TemplatePreviewResponse>();
|
||||
var preview = await response.Content.ReadFromJsonAsync<TemplatePreviewResponse>(cancellationToken: CancellationToken.None);
|
||||
Assert.NotNull(preview);
|
||||
Assert.Contains("Hello World", preview.RenderedBody);
|
||||
Assert.Contains("5", preview.RenderedBody);
|
||||
@@ -202,11 +202,11 @@ public sealed class NotifyApiEndpointsTests : IClassFixture<WebApplicationFactor
|
||||
};
|
||||
|
||||
// Act
|
||||
var response = await _client.PostAsJsonAsync("/api/v2/notify/templates/validate", request);
|
||||
var response = await _client.PostAsJsonAsync("/api/v2/notify/templates/validate", request, cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
|
||||
var result = await response.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: CancellationToken.None);
|
||||
Assert.True(result.GetProperty("isValid").GetBoolean());
|
||||
}
|
||||
|
||||
@@ -220,11 +220,11 @@ public sealed class NotifyApiEndpointsTests : IClassFixture<WebApplicationFactor
|
||||
};
|
||||
|
||||
// Act
|
||||
var response = await _client.PostAsJsonAsync("/api/v2/notify/templates/validate", request);
|
||||
var response = await _client.PostAsJsonAsync("/api/v2/notify/templates/validate", request, cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var result = await response.Content.ReadFromJsonAsync<JsonElement>();
|
||||
var result = await response.Content.ReadFromJsonAsync<JsonElement>(cancellationToken: CancellationToken.None);
|
||||
Assert.False(result.GetProperty("isValid").GetBoolean());
|
||||
}
|
||||
|
||||
@@ -236,11 +236,11 @@ public sealed class NotifyApiEndpointsTests : IClassFixture<WebApplicationFactor
|
||||
public async Task GetIncidents_ReturnsIncidentList()
|
||||
{
|
||||
// Act
|
||||
var response = await _client.GetAsync("/api/v2/notify/incidents");
|
||||
var response = await _client.GetAsync("/api/v2/notify/incidents", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var result = await response.Content.ReadFromJsonAsync<IncidentListResponse>();
|
||||
var result = await response.Content.ReadFromJsonAsync<IncidentListResponse>(cancellationToken: CancellationToken.None);
|
||||
Assert.NotNull(result);
|
||||
Assert.NotNull(result.Incidents);
|
||||
}
|
||||
@@ -256,7 +256,7 @@ public sealed class NotifyApiEndpointsTests : IClassFixture<WebApplicationFactor
|
||||
};
|
||||
|
||||
// Act
|
||||
var response = await _client.PostAsJsonAsync("/api/v2/notify/incidents/incident-001/ack", request);
|
||||
var response = await _client.PostAsJsonAsync("/api/v2/notify/incidents/incident-001/ack", request, cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
|
||||
@@ -273,7 +273,7 @@ public sealed class NotifyApiEndpointsTests : IClassFixture<WebApplicationFactor
|
||||
var clientWithoutTenant = _factory.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await clientWithoutTenant.GetAsync("/api/v2/notify/rules");
|
||||
var response = await clientWithoutTenant.GetAsync("/api/v2/notify/rules", CancellationToken.None);
|
||||
|
||||
// Assert - should fail without tenant header
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
|
||||
@@ -82,10 +82,10 @@ public sealed class EventProcessorTests
|
||||
actor: "policy-engine",
|
||||
version: "1");
|
||||
|
||||
var deliveriesFirst = await processor.ProcessAsync(notifyEvent, "worker-1", TestContext.Current.CancellationToken);
|
||||
var deliveriesFirst = await processor.ProcessAsync(notifyEvent, "worker-1", CancellationToken.None);
|
||||
var key = IdempotencyKeyBuilder.Build("tenant-a", rule.RuleId, "act-slack", notifyEvent);
|
||||
var reservedAfterFirst = await lockRepository.TryAcquireAsync("tenant-a", key, "worker-verify", TimeSpan.FromMinutes(5), TestContext.Current.CancellationToken);
|
||||
var deliveriesSecond = await processor.ProcessAsync(notifyEvent, "worker-1", TestContext.Current.CancellationToken);
|
||||
var reservedAfterFirst = await lockRepository.TryAcquireAsync("tenant-a", key, "worker-verify", TimeSpan.FromMinutes(5), CancellationToken.None);
|
||||
var deliveriesSecond = await processor.ProcessAsync(notifyEvent, "worker-1", CancellationToken.None);
|
||||
|
||||
Assert.Equal(1, deliveriesFirst);
|
||||
Assert.False(reservedAfterFirst);
|
||||
@@ -187,7 +187,7 @@ public sealed class EventProcessorTests
|
||||
actor: "policy-engine",
|
||||
version: "1");
|
||||
|
||||
var deliveries = await processor.ProcessAsync(notifyEvent, "worker-1", TestContext.Current.CancellationToken);
|
||||
var deliveries = await processor.ProcessAsync(notifyEvent, "worker-1", CancellationToken.None);
|
||||
|
||||
Assert.Equal(1, deliveries);
|
||||
|
||||
@@ -259,7 +259,7 @@ public sealed class EventProcessorTests
|
||||
actor: "policy-engine",
|
||||
version: "1");
|
||||
|
||||
var deliveries = await processor.ProcessAsync(notifyEvent, "worker-1", TestContext.Current.CancellationToken);
|
||||
var deliveries = await processor.ProcessAsync(notifyEvent, "worker-1", CancellationToken.None);
|
||||
|
||||
Assert.Equal(1, deliveries);
|
||||
var record = Assert.Single(deliveryRepository.Records("tenant-a"));
|
||||
|
||||
@@ -37,10 +37,10 @@ public class InMemoryFallbackHandlerTests
|
||||
public async Task GetFallbackAsync_FirstFailure_ReturnsNextChannel()
|
||||
{
|
||||
// Arrange
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Slack, "Connection timeout");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Slack, "Connection timeout", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery1");
|
||||
var result = await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.HasFallback);
|
||||
@@ -53,13 +53,13 @@ public class InMemoryFallbackHandlerTests
|
||||
public async Task GetFallbackAsync_SecondFailure_ReturnsThirdChannel()
|
||||
{
|
||||
// Arrange
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Slack, "Connection timeout");
|
||||
await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery1");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Slack, "Connection timeout", CancellationToken.None);
|
||||
await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery1", CancellationToken.None);
|
||||
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Teams, "Rate limited");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Teams, "Rate limited", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Teams, "delivery1");
|
||||
var result = await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Teams, "delivery1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.HasFallback);
|
||||
@@ -71,16 +71,16 @@ public class InMemoryFallbackHandlerTests
|
||||
public async Task GetFallbackAsync_AllChannelsFailed_ReturnsExhausted()
|
||||
{
|
||||
// Arrange - exhaust all channels (Slack -> Teams -> Email)
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Slack, "Failed");
|
||||
await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery1");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Slack, "Failed", CancellationToken.None);
|
||||
await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery1", CancellationToken.None);
|
||||
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Teams, "Failed");
|
||||
await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Teams, "delivery1");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Teams, "Failed", CancellationToken.None);
|
||||
await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Teams, "delivery1", CancellationToken.None);
|
||||
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Email, "Failed");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Email, "Failed", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Email, "delivery1");
|
||||
var result = await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Email, "delivery1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.HasFallback);
|
||||
@@ -93,8 +93,8 @@ public class InMemoryFallbackHandlerTests
|
||||
public async Task GetFallbackAsync_NoFallbackConfigured_ReturnsNoFallback()
|
||||
{
|
||||
// Act - Webhook has no fallback chain
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Webhook, "Failed");
|
||||
var result = await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Webhook, "delivery1");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Webhook, "Failed", CancellationToken.None);
|
||||
var result = await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Webhook, "delivery1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.HasFallback);
|
||||
@@ -112,7 +112,7 @@ public class InMemoryFallbackHandlerTests
|
||||
NullLogger<InMemoryFallbackHandler>.Instance);
|
||||
|
||||
// Act
|
||||
var result = await disabledHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery1");
|
||||
var result = await disabledHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.HasFallback);
|
||||
@@ -122,14 +122,14 @@ public class InMemoryFallbackHandlerTests
|
||||
public async Task RecordSuccessAsync_MarksDeliveryAsSucceeded()
|
||||
{
|
||||
// Arrange
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Slack, "Failed");
|
||||
await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery1");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Slack, "Failed", CancellationToken.None);
|
||||
await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery1", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
await _fallbackHandler.RecordSuccessAsync("tenant1", "delivery1", NotifyChannelType.Teams);
|
||||
await _fallbackHandler.RecordSuccessAsync("tenant1", "delivery1", NotifyChannelType.Teams, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var stats = await _fallbackHandler.GetStatisticsAsync("tenant1");
|
||||
var stats = await _fallbackHandler.GetStatisticsAsync("tenant1", cancellationToken: CancellationToken.None);
|
||||
Assert.Equal(1, stats.FallbackSuccesses);
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ public class InMemoryFallbackHandlerTests
|
||||
public async Task GetFallbackChainAsync_ReturnsDefaultChain()
|
||||
{
|
||||
// Act
|
||||
var chain = await _fallbackHandler.GetFallbackChainAsync("tenant1", NotifyChannelType.Slack);
|
||||
var chain = await _fallbackHandler.GetFallbackChainAsync("tenant1", NotifyChannelType.Slack, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, chain.Count);
|
||||
@@ -149,13 +149,9 @@ public class InMemoryFallbackHandlerTests
|
||||
public async Task SetFallbackChainAsync_CreatesTenantSpecificChain()
|
||||
{
|
||||
// Act
|
||||
await _fallbackHandler.SetFallbackChainAsync(
|
||||
"tenant1",
|
||||
NotifyChannelType.Slack,
|
||||
[NotifyChannelType.Webhook, NotifyChannelType.Email],
|
||||
"admin");
|
||||
await _fallbackHandler.SetFallbackChainAsync("tenant1", NotifyChannelType.Slack, [NotifyChannelType.Webhook, NotifyChannelType.Email], "admin", CancellationToken.None);
|
||||
|
||||
var chain = await _fallbackHandler.GetFallbackChainAsync("tenant1", NotifyChannelType.Slack);
|
||||
var chain = await _fallbackHandler.GetFallbackChainAsync("tenant1", NotifyChannelType.Slack, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, chain.Count);
|
||||
@@ -167,15 +163,11 @@ public class InMemoryFallbackHandlerTests
|
||||
public async Task SetFallbackChainAsync_DoesNotAffectOtherTenants()
|
||||
{
|
||||
// Arrange
|
||||
await _fallbackHandler.SetFallbackChainAsync(
|
||||
"tenant1",
|
||||
NotifyChannelType.Slack,
|
||||
[NotifyChannelType.Webhook],
|
||||
"admin");
|
||||
await _fallbackHandler.SetFallbackChainAsync("tenant1", NotifyChannelType.Slack, [NotifyChannelType.Webhook], "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var tenant1Chain = await _fallbackHandler.GetFallbackChainAsync("tenant1", NotifyChannelType.Slack);
|
||||
var tenant2Chain = await _fallbackHandler.GetFallbackChainAsync("tenant2", NotifyChannelType.Slack);
|
||||
var tenant1Chain = await _fallbackHandler.GetFallbackChainAsync("tenant1", NotifyChannelType.Slack, CancellationToken.None);
|
||||
var tenant2Chain = await _fallbackHandler.GetFallbackChainAsync("tenant2", NotifyChannelType.Slack, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Single(tenant1Chain);
|
||||
@@ -190,18 +182,18 @@ public class InMemoryFallbackHandlerTests
|
||||
{
|
||||
// Arrange - Create various delivery scenarios
|
||||
// Delivery 1: Primary success
|
||||
await _fallbackHandler.RecordSuccessAsync("tenant1", "delivery1", NotifyChannelType.Slack);
|
||||
await _fallbackHandler.RecordSuccessAsync("tenant1", "delivery1", NotifyChannelType.Slack, CancellationToken.None);
|
||||
|
||||
// Delivery 2: Fallback success
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery2", NotifyChannelType.Slack, "Failed");
|
||||
await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery2");
|
||||
await _fallbackHandler.RecordSuccessAsync("tenant1", "delivery2", NotifyChannelType.Teams);
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery2", NotifyChannelType.Slack, "Failed", CancellationToken.None);
|
||||
await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery2", CancellationToken.None);
|
||||
await _fallbackHandler.RecordSuccessAsync("tenant1", "delivery2", NotifyChannelType.Teams, CancellationToken.None);
|
||||
|
||||
// Delivery 3: Exhausted
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery3", NotifyChannelType.Webhook, "Failed");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery3", NotifyChannelType.Webhook, "Failed", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var stats = await _fallbackHandler.GetStatisticsAsync("tenant1");
|
||||
var stats = await _fallbackHandler.GetStatisticsAsync("tenant1", cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("tenant1", stats.TenantId);
|
||||
@@ -215,14 +207,14 @@ public class InMemoryFallbackHandlerTests
|
||||
public async Task GetStatisticsAsync_FiltersWithinWindow()
|
||||
{
|
||||
// Arrange
|
||||
await _fallbackHandler.RecordSuccessAsync("tenant1", "old-delivery", NotifyChannelType.Slack);
|
||||
await _fallbackHandler.RecordSuccessAsync("tenant1", "old-delivery", NotifyChannelType.Slack, CancellationToken.None);
|
||||
|
||||
_timeProvider.Advance(TimeSpan.FromHours(25));
|
||||
|
||||
await _fallbackHandler.RecordSuccessAsync("tenant1", "recent-delivery", NotifyChannelType.Slack);
|
||||
await _fallbackHandler.RecordSuccessAsync("tenant1", "recent-delivery", NotifyChannelType.Slack, CancellationToken.None);
|
||||
|
||||
// Act - Get stats for last 24 hours
|
||||
var stats = await _fallbackHandler.GetStatisticsAsync("tenant1", TimeSpan.FromHours(24));
|
||||
var stats = await _fallbackHandler.GetStatisticsAsync("tenant1", TimeSpan.FromHours(24), CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, stats.TotalDeliveries);
|
||||
@@ -232,15 +224,15 @@ public class InMemoryFallbackHandlerTests
|
||||
public async Task ClearDeliveryStateAsync_RemovesDeliveryTracking()
|
||||
{
|
||||
// Arrange
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Slack, "Failed");
|
||||
await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery1");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Slack, "Failed", CancellationToken.None);
|
||||
await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery1", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
await _fallbackHandler.ClearDeliveryStateAsync("tenant1", "delivery1");
|
||||
await _fallbackHandler.ClearDeliveryStateAsync("tenant1", "delivery1", CancellationToken.None);
|
||||
|
||||
// Get fallback again - should start fresh
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Slack, "Failed again");
|
||||
var result = await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery1");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Slack, "Failed again", CancellationToken.None);
|
||||
var result = await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery1", CancellationToken.None);
|
||||
|
||||
// Assert - Should be back to first fallback attempt
|
||||
Assert.Equal(NotifyChannelType.Teams, result.NextChannelType);
|
||||
@@ -252,23 +244,19 @@ public class InMemoryFallbackHandlerTests
|
||||
{
|
||||
// Arrange - MaxAttempts is 3, but chain has 4 channels (Slack + 3 fallbacks would exceed)
|
||||
// Add a longer chain
|
||||
await _fallbackHandler.SetFallbackChainAsync(
|
||||
"tenant1",
|
||||
NotifyChannelType.Slack,
|
||||
[NotifyChannelType.Teams, NotifyChannelType.Email, NotifyChannelType.Webhook, NotifyChannelType.Custom],
|
||||
"admin");
|
||||
await _fallbackHandler.SetFallbackChainAsync("tenant1", NotifyChannelType.Slack, [NotifyChannelType.Teams, NotifyChannelType.Email, NotifyChannelType.Webhook, NotifyChannelType.Custom], "admin", CancellationToken.None);
|
||||
|
||||
// Fail through 3 attempts (max)
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Slack, "Failed");
|
||||
await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery1");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Slack, "Failed", CancellationToken.None);
|
||||
await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery1", CancellationToken.None);
|
||||
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Teams, "Failed");
|
||||
await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Teams, "delivery1");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Teams, "Failed", CancellationToken.None);
|
||||
await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Teams, "delivery1", CancellationToken.None);
|
||||
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Email, "Failed");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Email, "Failed", CancellationToken.None);
|
||||
|
||||
// Act - 4th attempt should be blocked by MaxAttempts
|
||||
var result = await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Email, "delivery1");
|
||||
var result = await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Email, "delivery1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsExhausted);
|
||||
@@ -278,11 +266,11 @@ public class InMemoryFallbackHandlerTests
|
||||
public async Task RecordFailureAsync_TracksMultipleFailures()
|
||||
{
|
||||
// Arrange & Act
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Slack, "Timeout");
|
||||
await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery1");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Slack, "Timeout", CancellationToken.None);
|
||||
await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Slack, "delivery1", CancellationToken.None);
|
||||
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Teams, "Rate limited");
|
||||
var result = await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Teams, "delivery1");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "delivery1", NotifyChannelType.Teams, "Rate limited", CancellationToken.None);
|
||||
var result = await _fallbackHandler.GetFallbackAsync("tenant1", NotifyChannelType.Teams, "delivery1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, result.FailedChannels.Count);
|
||||
@@ -294,12 +282,12 @@ public class InMemoryFallbackHandlerTests
|
||||
public async Task GetStatisticsAsync_TracksFailuresByChannel()
|
||||
{
|
||||
// Arrange
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "d1", NotifyChannelType.Slack, "Failed");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "d2", NotifyChannelType.Slack, "Failed");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "d3", NotifyChannelType.Teams, "Failed");
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "d1", NotifyChannelType.Slack, "Failed", CancellationToken.None);
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "d2", NotifyChannelType.Slack, "Failed", CancellationToken.None);
|
||||
await _fallbackHandler.RecordFailureAsync("tenant1", "d3", NotifyChannelType.Teams, "Failed", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var stats = await _fallbackHandler.GetStatisticsAsync("tenant1");
|
||||
var stats = await _fallbackHandler.GetStatisticsAsync("tenant1", cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, stats.FailuresByChannel[NotifyChannelType.Slack]);
|
||||
|
||||
@@ -33,7 +33,7 @@ public class InMemoryLocalizationServiceTests
|
||||
public async Task GetStringAsync_SystemBundle_ReturnsValue()
|
||||
{
|
||||
// Act - system bundles are seeded automatically
|
||||
var value = await _localizationService.GetStringAsync("tenant1", "storm.detected.title", "en-US");
|
||||
var value = await _localizationService.GetStringAsync("tenant1", "storm.detected.title", "en-US", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(value);
|
||||
@@ -44,7 +44,7 @@ public class InMemoryLocalizationServiceTests
|
||||
public async Task GetStringAsync_GermanLocale_ReturnsGermanValue()
|
||||
{
|
||||
// Act
|
||||
var value = await _localizationService.GetStringAsync("tenant1", "storm.detected.title", "de-DE");
|
||||
var value = await _localizationService.GetStringAsync("tenant1", "storm.detected.title", "de-DE", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(value);
|
||||
@@ -55,7 +55,7 @@ public class InMemoryLocalizationServiceTests
|
||||
public async Task GetStringAsync_FrenchLocale_ReturnsFrenchValue()
|
||||
{
|
||||
// Act
|
||||
var value = await _localizationService.GetStringAsync("tenant1", "storm.detected.title", "fr-FR");
|
||||
var value = await _localizationService.GetStringAsync("tenant1", "storm.detected.title", "fr-FR", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(value);
|
||||
@@ -66,7 +66,7 @@ public class InMemoryLocalizationServiceTests
|
||||
public async Task GetStringAsync_UnknownKey_ReturnsKey()
|
||||
{
|
||||
// Act
|
||||
var value = await _localizationService.GetStringAsync("tenant1", "unknown.key", "en-US");
|
||||
var value = await _localizationService.GetStringAsync("tenant1", "unknown.key", "en-US", CancellationToken.None);
|
||||
|
||||
// Assert (when ReturnKeyWhenMissing = true)
|
||||
Assert.Equal("unknown.key", value);
|
||||
@@ -76,7 +76,7 @@ public class InMemoryLocalizationServiceTests
|
||||
public async Task GetStringAsync_LocaleFallback_UsesDefaultLocale()
|
||||
{
|
||||
// Act - Japanese locale (not configured) should fall back to en-US
|
||||
var value = await _localizationService.GetStringAsync("tenant1", "storm.detected.title", "ja-JP");
|
||||
var value = await _localizationService.GetStringAsync("tenant1", "storm.detected.title", "ja-JP", CancellationToken.None);
|
||||
|
||||
// Assert - should get en-US value
|
||||
Assert.Equal("Notification Storm Detected", value);
|
||||
@@ -92,8 +92,7 @@ public class InMemoryLocalizationServiceTests
|
||||
["count"] = 50,
|
||||
["window"] = "5 minutes"
|
||||
};
|
||||
var value = await _localizationService.GetFormattedStringAsync(
|
||||
"tenant1", "storm.detected.body", "en-US", parameters);
|
||||
var value = await _localizationService.GetFormattedStringAsync("tenant1", "storm.detected.body", "en-US", parameters, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(value);
|
||||
@@ -120,7 +119,7 @@ public class InMemoryLocalizationServiceTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _localizationService.UpsertBundleAsync(bundle, "admin");
|
||||
var result = await _localizationService.UpsertBundleAsync(bundle, "admin", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Success);
|
||||
@@ -128,7 +127,7 @@ public class InMemoryLocalizationServiceTests
|
||||
Assert.Equal("tenant-bundle", result.BundleId);
|
||||
|
||||
// Verify string is accessible
|
||||
var greeting = await _localizationService.GetStringAsync("tenant1", "custom.greeting", "en-US");
|
||||
var greeting = await _localizationService.GetStringAsync("tenant1", "custom.greeting", "en-US", CancellationToken.None);
|
||||
Assert.Equal("Hello, World!", greeting);
|
||||
}
|
||||
|
||||
@@ -146,7 +145,7 @@ public class InMemoryLocalizationServiceTests
|
||||
["test.key"] = "Original value"
|
||||
}
|
||||
};
|
||||
await _localizationService.UpsertBundleAsync(bundle, "admin");
|
||||
await _localizationService.UpsertBundleAsync(bundle, "admin", CancellationToken.None);
|
||||
|
||||
// Act - update with new value
|
||||
var updatedBundle = bundle with
|
||||
@@ -156,13 +155,13 @@ public class InMemoryLocalizationServiceTests
|
||||
["test.key"] = "Updated value"
|
||||
}
|
||||
};
|
||||
var result = await _localizationService.UpsertBundleAsync(updatedBundle, "admin");
|
||||
var result = await _localizationService.UpsertBundleAsync(updatedBundle, "admin", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Success);
|
||||
Assert.False(result.IsNew);
|
||||
|
||||
var value = await _localizationService.GetStringAsync("tenant1", "test.key", "en-US");
|
||||
var value = await _localizationService.GetStringAsync("tenant1", "test.key", "en-US", CancellationToken.None);
|
||||
Assert.Equal("Updated value", value);
|
||||
}
|
||||
|
||||
@@ -180,15 +179,15 @@ public class InMemoryLocalizationServiceTests
|
||||
["delete.key"] = "Will be deleted"
|
||||
}
|
||||
};
|
||||
await _localizationService.UpsertBundleAsync(bundle, "admin");
|
||||
await _localizationService.UpsertBundleAsync(bundle, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var deleted = await _localizationService.DeleteBundleAsync("tenant1", "delete-test", "admin");
|
||||
var deleted = await _localizationService.DeleteBundleAsync("tenant1", "delete-test", "admin", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(deleted);
|
||||
|
||||
var bundles = await _localizationService.ListBundlesAsync("tenant1");
|
||||
var bundles = await _localizationService.ListBundlesAsync("tenant1", CancellationToken.None);
|
||||
Assert.DoesNotContain(bundles, b => b.BundleId == "delete-test");
|
||||
}
|
||||
|
||||
@@ -218,12 +217,12 @@ public class InMemoryLocalizationServiceTests
|
||||
Strings = new Dictionary<string, string> { ["key3"] = "value3" }
|
||||
};
|
||||
|
||||
await _localizationService.UpsertBundleAsync(bundle1, "admin");
|
||||
await _localizationService.UpsertBundleAsync(bundle2, "admin");
|
||||
await _localizationService.UpsertBundleAsync(bundle3, "admin");
|
||||
await _localizationService.UpsertBundleAsync(bundle1, "admin", CancellationToken.None);
|
||||
await _localizationService.UpsertBundleAsync(bundle2, "admin", CancellationToken.None);
|
||||
await _localizationService.UpsertBundleAsync(bundle3, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var tenant1Bundles = await _localizationService.ListBundlesAsync("tenant1");
|
||||
var tenant1Bundles = await _localizationService.ListBundlesAsync("tenant1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, tenant1Bundles.Count);
|
||||
@@ -236,7 +235,7 @@ public class InMemoryLocalizationServiceTests
|
||||
public async Task GetSupportedLocalesAsync_ReturnsAvailableLocales()
|
||||
{
|
||||
// Act
|
||||
var locales = await _localizationService.GetSupportedLocalesAsync("tenant1");
|
||||
var locales = await _localizationService.GetSupportedLocalesAsync("tenant1", CancellationToken.None);
|
||||
|
||||
// Assert - should include seeded system locales
|
||||
Assert.Contains("en-US", locales);
|
||||
@@ -260,10 +259,10 @@ public class InMemoryLocalizationServiceTests
|
||||
["tenant.custom"] = "Custom Value"
|
||||
}
|
||||
};
|
||||
await _localizationService.UpsertBundleAsync(tenantBundle, "admin");
|
||||
await _localizationService.UpsertBundleAsync(tenantBundle, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var bundle = await _localizationService.GetBundleAsync("tenant1", "en-US");
|
||||
var bundle = await _localizationService.GetBundleAsync("tenant1", "en-US", CancellationToken.None);
|
||||
|
||||
// Assert - should have both system and tenant strings, with tenant override
|
||||
Assert.True(bundle.ContainsKey("storm.detected.title"));
|
||||
@@ -359,13 +358,13 @@ public class InMemoryLocalizationServiceTests
|
||||
public async Task GetStringAsync_CachesResults()
|
||||
{
|
||||
// Act - first call
|
||||
var value1 = await _localizationService.GetStringAsync("tenant1", "storm.detected.title", "en-US");
|
||||
var value1 = await _localizationService.GetStringAsync("tenant1", "storm.detected.title", "en-US", CancellationToken.None);
|
||||
|
||||
// Advance time slightly (within cache duration)
|
||||
_timeProvider.Advance(TimeSpan.FromMinutes(5));
|
||||
|
||||
// Second call should hit cache
|
||||
var value2 = await _localizationService.GetStringAsync("tenant1", "storm.detected.title", "en-US");
|
||||
var value2 = await _localizationService.GetStringAsync("tenant1", "storm.detected.title", "en-US", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(value1, value2);
|
||||
@@ -385,12 +384,11 @@ public class InMemoryLocalizationServiceTests
|
||||
["number.test"] = "Total: {{count}} items"
|
||||
}
|
||||
};
|
||||
await _localizationService.UpsertBundleAsync(bundle, "admin");
|
||||
await _localizationService.UpsertBundleAsync(bundle, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var parameters = new Dictionary<string, object> { ["count"] = 1234567 };
|
||||
var value = await _localizationService.GetFormattedStringAsync(
|
||||
"tenant1", "number.test", "de-DE", parameters);
|
||||
var value = await _localizationService.GetFormattedStringAsync("tenant1", "number.test", "de-DE", parameters, CancellationToken.None);
|
||||
|
||||
// Assert - German number formatting uses periods as thousands separator
|
||||
Assert.Contains("1.234.567", value);
|
||||
|
||||
@@ -41,7 +41,7 @@ public class ChaosTestRunnerTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var experiment = await _runner.StartExperimentAsync(config);
|
||||
var experiment = await _runner.StartExperimentAsync(config, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(experiment);
|
||||
@@ -68,7 +68,7 @@ public class ChaosTestRunnerTests
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() => runner.StartExperimentAsync(config));
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() => runner.StartExperimentAsync(config, CancellationToken.None));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -84,7 +84,7 @@ public class ChaosTestRunnerTests
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() => _runner.StartExperimentAsync(config));
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(() => _runner.StartExperimentAsync(config, CancellationToken.None));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -98,7 +98,7 @@ public class ChaosTestRunnerTests
|
||||
Name = $"Experiment {i}",
|
||||
InitiatedBy = "test-user",
|
||||
FaultType = ChaosFaultType.Outage
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
}
|
||||
|
||||
// Act & Assert
|
||||
@@ -108,7 +108,7 @@ public class ChaosTestRunnerTests
|
||||
Name = "One too many",
|
||||
InitiatedBy = "test-user",
|
||||
FaultType = ChaosFaultType.Outage
|
||||
}));
|
||||
}, CancellationToken.None));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -120,13 +120,13 @@ public class ChaosTestRunnerTests
|
||||
Name = "Test",
|
||||
InitiatedBy = "test-user",
|
||||
FaultType = ChaosFaultType.Outage
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
await _runner.StopExperimentAsync(experiment.Id);
|
||||
await _runner.StopExperimentAsync(experiment.Id, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var stopped = await _runner.GetExperimentAsync(experiment.Id);
|
||||
var stopped = await _runner.GetExperimentAsync(experiment.Id, CancellationToken.None);
|
||||
Assert.NotNull(stopped);
|
||||
Assert.Equal(ChaosExperimentStatus.Stopped, stopped.Status);
|
||||
Assert.NotNull(stopped.EndedAt);
|
||||
@@ -143,10 +143,10 @@ public class ChaosTestRunnerTests
|
||||
TenantId = "tenant1",
|
||||
TargetChannelTypes = ["email"],
|
||||
FaultType = ChaosFaultType.Outage
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var decision = await _runner.ShouldFailAsync("tenant1", "email");
|
||||
var decision = await _runner.ShouldFailAsync("tenant1", "email", ct: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(decision.ShouldFail);
|
||||
@@ -165,10 +165,10 @@ public class ChaosTestRunnerTests
|
||||
TenantId = "tenant1",
|
||||
TargetChannelTypes = ["email"],
|
||||
FaultType = ChaosFaultType.Outage
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Act - different tenant
|
||||
var decision = await _runner.ShouldFailAsync("tenant2", "email");
|
||||
var decision = await _runner.ShouldFailAsync("tenant2", "email", ct: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(decision.ShouldFail);
|
||||
@@ -185,10 +185,10 @@ public class ChaosTestRunnerTests
|
||||
TenantId = "tenant1",
|
||||
TargetChannelTypes = ["email"],
|
||||
FaultType = ChaosFaultType.Outage
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Act - different channel type
|
||||
var decision = await _runner.ShouldFailAsync("tenant1", "slack");
|
||||
var decision = await _runner.ShouldFailAsync("tenant1", "slack", ct: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(decision.ShouldFail);
|
||||
@@ -210,10 +210,10 @@ public class ChaosTestRunnerTests
|
||||
MinLatency = TimeSpan.FromSeconds(1),
|
||||
MaxLatency = TimeSpan.FromSeconds(5)
|
||||
}
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var decision = await _runner.ShouldFailAsync("tenant1", "email");
|
||||
var decision = await _runner.ShouldFailAsync("tenant1", "email", ct: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(decision.ShouldFail); // Latency doesn't cause failure
|
||||
@@ -237,13 +237,13 @@ public class ChaosTestRunnerTests
|
||||
FailureRate = 0.5,
|
||||
Seed = 42 // Fixed seed for reproducibility
|
||||
}
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Act - run multiple times
|
||||
var failures = 0;
|
||||
for (var i = 0; i < 100; i++)
|
||||
{
|
||||
var decision = await _runner.ShouldFailAsync("tenant1", "email");
|
||||
var decision = await _runner.ShouldFailAsync("tenant1", "email", ct: CancellationToken.None);
|
||||
if (decision.ShouldFail) failures++;
|
||||
}
|
||||
|
||||
@@ -266,17 +266,17 @@ public class ChaosTestRunnerTests
|
||||
{
|
||||
RateLimitPerMinute = 5
|
||||
}
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Act - first 5 should pass
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
var decision = await _runner.ShouldFailAsync("tenant1", "email");
|
||||
var decision = await _runner.ShouldFailAsync("tenant1", "email", ct: CancellationToken.None);
|
||||
Assert.False(decision.ShouldFail);
|
||||
}
|
||||
|
||||
// 6th should fail
|
||||
var failedDecision = await _runner.ShouldFailAsync("tenant1", "email");
|
||||
var failedDecision = await _runner.ShouldFailAsync("tenant1", "email", ct: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(failedDecision.ShouldFail);
|
||||
@@ -295,11 +295,11 @@ public class ChaosTestRunnerTests
|
||||
TargetChannelTypes = ["email"],
|
||||
FaultType = ChaosFaultType.Outage,
|
||||
Duration = TimeSpan.FromMinutes(5)
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Act - advance time past duration
|
||||
_timeProvider.Advance(TimeSpan.FromMinutes(10));
|
||||
var decision = await _runner.ShouldFailAsync("tenant1", "email");
|
||||
var decision = await _runner.ShouldFailAsync("tenant1", "email", ct: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(decision.ShouldFail);
|
||||
@@ -317,17 +317,17 @@ public class ChaosTestRunnerTests
|
||||
TargetChannelTypes = ["email"],
|
||||
FaultType = ChaosFaultType.Outage,
|
||||
MaxAffectedOperations = 3
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Act - consume all operations
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
var d = await _runner.ShouldFailAsync("tenant1", "email");
|
||||
var d = await _runner.ShouldFailAsync("tenant1", "email", ct: CancellationToken.None);
|
||||
Assert.True(d.ShouldFail);
|
||||
}
|
||||
|
||||
// 4th should not match
|
||||
var decision = await _runner.ShouldFailAsync("tenant1", "email");
|
||||
var decision = await _runner.ShouldFailAsync("tenant1", "email", ct: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(decision.ShouldFail);
|
||||
@@ -342,7 +342,7 @@ public class ChaosTestRunnerTests
|
||||
Name = "Test",
|
||||
InitiatedBy = "test-user",
|
||||
FaultType = ChaosFaultType.Outage
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
await _runner.RecordOutcomeAsync(experiment.Id, new ChaosOutcome
|
||||
@@ -351,9 +351,9 @@ public class ChaosTestRunnerTests
|
||||
ChannelType = "email",
|
||||
TenantId = "tenant1",
|
||||
FallbackTriggered = true
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
var results = await _runner.GetResultsAsync(experiment.Id);
|
||||
var results = await _runner.GetResultsAsync(experiment.Id, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, results.TotalAffected);
|
||||
@@ -370,7 +370,7 @@ public class ChaosTestRunnerTests
|
||||
Name = "Test",
|
||||
InitiatedBy = "test-user",
|
||||
FaultType = ChaosFaultType.Latency
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Record various outcomes
|
||||
await _runner.RecordOutcomeAsync(experiment.Id, new ChaosOutcome
|
||||
@@ -378,22 +378,22 @@ public class ChaosTestRunnerTests
|
||||
Type = ChaosOutcomeType.LatencyInjected,
|
||||
ChannelType = "email",
|
||||
Duration = TimeSpan.FromMilliseconds(100)
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
await _runner.RecordOutcomeAsync(experiment.Id, new ChaosOutcome
|
||||
{
|
||||
Type = ChaosOutcomeType.LatencyInjected,
|
||||
ChannelType = "email",
|
||||
Duration = TimeSpan.FromMilliseconds(200)
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
await _runner.RecordOutcomeAsync(experiment.Id, new ChaosOutcome
|
||||
{
|
||||
Type = ChaosOutcomeType.FaultInjected,
|
||||
ChannelType = "slack",
|
||||
FallbackTriggered = true
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var results = await _runner.GetResultsAsync(experiment.Id);
|
||||
var results = await _runner.GetResultsAsync(experiment.Id, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, results.TotalAffected);
|
||||
@@ -414,19 +414,19 @@ public class ChaosTestRunnerTests
|
||||
Name = "Running",
|
||||
InitiatedBy = "test-user",
|
||||
FaultType = ChaosFaultType.Outage
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
var toStop = await _runner.StartExperimentAsync(new ChaosExperimentConfig
|
||||
{
|
||||
Name = "To Stop",
|
||||
InitiatedBy = "test-user",
|
||||
FaultType = ChaosFaultType.Outage
|
||||
});
|
||||
await _runner.StopExperimentAsync(toStop.Id);
|
||||
}, CancellationToken.None);
|
||||
await _runner.StopExperimentAsync(toStop.Id, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var runningList = await _runner.ListExperimentsAsync(ChaosExperimentStatus.Running);
|
||||
var stoppedList = await _runner.ListExperimentsAsync(ChaosExperimentStatus.Stopped);
|
||||
var runningList = await _runner.ListExperimentsAsync(ChaosExperimentStatus.Running, ct: CancellationToken.None);
|
||||
var stoppedList = await _runner.ListExperimentsAsync(ChaosExperimentStatus.Stopped, ct: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Single(runningList);
|
||||
@@ -445,21 +445,21 @@ public class ChaosTestRunnerTests
|
||||
InitiatedBy = "test-user",
|
||||
FaultType = ChaosFaultType.Outage,
|
||||
Duration = TimeSpan.FromMinutes(5)
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Complete the experiment
|
||||
_timeProvider.Advance(TimeSpan.FromMinutes(10));
|
||||
await _runner.GetExperimentAsync(experiment.Id); // Triggers status update
|
||||
await _runner.GetExperimentAsync(experiment.Id, CancellationToken.None); // Triggers status update
|
||||
|
||||
// Advance time beyond cleanup threshold
|
||||
_timeProvider.Advance(TimeSpan.FromDays(10));
|
||||
|
||||
// Act
|
||||
var removed = await _runner.CleanupAsync(TimeSpan.FromDays(7));
|
||||
var removed = await _runner.CleanupAsync(TimeSpan.FromDays(7), CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, removed);
|
||||
var result = await _runner.GetExperimentAsync(experiment.Id);
|
||||
var result = await _runner.GetExperimentAsync(experiment.Id, CancellationToken.None);
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
@@ -479,10 +479,10 @@ public class ChaosTestRunnerTests
|
||||
ErrorStatusCode = 503,
|
||||
ErrorMessage = "Service Unavailable"
|
||||
}
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var decision = await _runner.ShouldFailAsync("tenant1", "email");
|
||||
var decision = await _runner.ShouldFailAsync("tenant1", "email", ct: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(decision.ShouldFail);
|
||||
|
||||
@@ -20,13 +20,13 @@ public sealed class DeadLetterHandlerTests
|
||||
[Fact]
|
||||
public async Task DeadLetterAsync_AddsEntryAndUpdatesStats()
|
||||
{
|
||||
var entry = await _handler.DeadLetterAsync("tenant1", "delivery-001", DeadLetterReason.InvalidPayload, "webhook");
|
||||
var entry = await _handler.DeadLetterAsync("tenant1", "delivery-001", DeadLetterReason.InvalidPayload, "webhook", cancellationToken: CancellationToken.None);
|
||||
|
||||
Assert.NotNull(entry);
|
||||
Assert.Equal("tenant1", entry.TenantId);
|
||||
Assert.Equal(DeadLetterStatus.Pending, entry.Status);
|
||||
|
||||
var stats = await _handler.GetStatsAsync("tenant1");
|
||||
var stats = await _handler.GetStatsAsync("tenant1", CancellationToken.None);
|
||||
Assert.Equal(1, stats.PendingCount);
|
||||
Assert.Equal(1, stats.TotalCount);
|
||||
}
|
||||
@@ -34,38 +34,38 @@ public sealed class DeadLetterHandlerTests
|
||||
[Fact]
|
||||
public async Task RetryAsync_TransitionsStatus()
|
||||
{
|
||||
var entry = await _handler.DeadLetterAsync("tenant1", "delivery-002", DeadLetterReason.ChannelUnavailable, "email");
|
||||
var entry = await _handler.DeadLetterAsync("tenant1", "delivery-002", DeadLetterReason.ChannelUnavailable, "email", cancellationToken: CancellationToken.None);
|
||||
|
||||
var result = await _handler.RetryAsync("tenant1", entry.DeadLetterId);
|
||||
var result = await _handler.RetryAsync("tenant1", entry.DeadLetterId, CancellationToken.None);
|
||||
|
||||
Assert.True(result.Success);
|
||||
var list = await _handler.GetAsync("tenant1");
|
||||
var list = await _handler.GetAsync("tenant1", cancellationToken: CancellationToken.None);
|
||||
Assert.Equal(DeadLetterStatus.Retried, list.Single().Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DiscardAsync_RemovesFromPending()
|
||||
{
|
||||
var entry = await _handler.DeadLetterAsync("tenant1", "delivery-003", DeadLetterReason.ChannelUnavailable, "email");
|
||||
var entry = await _handler.DeadLetterAsync("tenant1", "delivery-003", DeadLetterReason.ChannelUnavailable, "email", cancellationToken: CancellationToken.None);
|
||||
|
||||
var discarded = await _handler.DiscardAsync("tenant1", entry.DeadLetterId, "manual");
|
||||
var discarded = await _handler.DiscardAsync("tenant1", entry.DeadLetterId, "manual", CancellationToken.None);
|
||||
|
||||
Assert.True(discarded);
|
||||
var list = await _handler.GetAsync("tenant1");
|
||||
var list = await _handler.GetAsync("tenant1", cancellationToken: CancellationToken.None);
|
||||
Assert.Equal(DeadLetterStatus.Discarded, list.Single().Status);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PurgeAsync_RemovesOlderThanCutoff()
|
||||
{
|
||||
await _handler.DeadLetterAsync("tenant1", "delivery-004", DeadLetterReason.ChannelUnavailable, "email");
|
||||
await _handler.DeadLetterAsync("tenant1", "delivery-004", DeadLetterReason.ChannelUnavailable, "email", cancellationToken: CancellationToken.None);
|
||||
_timeProvider.Advance(TimeSpan.FromDays(10));
|
||||
await _handler.DeadLetterAsync("tenant1", "delivery-005", DeadLetterReason.ChannelUnavailable, "email");
|
||||
await _handler.DeadLetterAsync("tenant1", "delivery-005", DeadLetterReason.ChannelUnavailable, "email", cancellationToken: CancellationToken.None);
|
||||
|
||||
var purged = await _handler.PurgeAsync("tenant1", TimeSpan.FromDays(7));
|
||||
var purged = await _handler.PurgeAsync("tenant1", TimeSpan.FromDays(7), CancellationToken.None);
|
||||
|
||||
Assert.Equal(1, purged);
|
||||
var remaining = await _handler.GetAsync("tenant1");
|
||||
var remaining = await _handler.GetAsync("tenant1", cancellationToken: CancellationToken.None);
|
||||
Assert.Single(remaining);
|
||||
Assert.Equal("delivery-005", remaining[0].DeliveryId);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ public class RetentionPolicyServiceTests
|
||||
[Fact]
|
||||
public async Task GetPolicyAsync_ReturnsDefault_WhenNoPolicySet()
|
||||
{
|
||||
var policy = await _service.GetPolicyAsync("tenant-default");
|
||||
var policy = await _service.GetPolicyAsync("tenant-default", CancellationToken.None);
|
||||
|
||||
Assert.Equal(RetentionPolicy.Default.DeadLetterRetention, policy.DeadLetterRetention);
|
||||
Assert.Equal(RetentionPolicy.Default.DeliveryRetention, policy.DeliveryRetention);
|
||||
@@ -41,9 +41,9 @@ public class RetentionPolicyServiceTests
|
||||
DeliveryRetention = TimeSpan.FromDays(45)
|
||||
};
|
||||
|
||||
await _service.SetPolicyAsync("tenant-42", policy);
|
||||
await _service.SetPolicyAsync("tenant-42", policy, CancellationToken.None);
|
||||
|
||||
var fetched = await _service.GetPolicyAsync("tenant-42");
|
||||
var fetched = await _service.GetPolicyAsync("tenant-42", CancellationToken.None);
|
||||
Assert.Equal(TimeSpan.FromDays(3), fetched.DeadLetterRetention);
|
||||
Assert.Equal(TimeSpan.FromDays(45), fetched.DeliveryRetention);
|
||||
}
|
||||
@@ -56,9 +56,9 @@ public class RetentionPolicyServiceTests
|
||||
await EnqueueDeadLetterAsync("tenant-1", "delivery-002", "event-002");
|
||||
|
||||
var policy = RetentionPolicy.Default with { DeadLetterRetention = TimeSpan.FromDays(1) };
|
||||
await _service.SetPolicyAsync("tenant-1", policy);
|
||||
await _service.SetPolicyAsync("tenant-1", policy, CancellationToken.None);
|
||||
|
||||
var result = await _service.ExecuteCleanupAsync("tenant-1");
|
||||
var result = await _service.ExecuteCleanupAsync("tenant-1", CancellationToken.None);
|
||||
|
||||
Assert.True(result.Success);
|
||||
Assert.Equal("tenant-1", result.TenantId);
|
||||
|
||||
@@ -24,7 +24,7 @@ public sealed class OpenApiEndpointTests : IClassFixture<NotifierApplicationFact
|
||||
[Fact]
|
||||
public async Task OpenApi_endpoint_serves_yaml_with_scope_header()
|
||||
{
|
||||
var response = await _client.GetAsync("/.well-known/openapi", TestContext.Current.CancellationToken);
|
||||
var response = await _client.GetAsync("/.well-known/openapi", CancellationToken.None);
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
}
|
||||
#endif
|
||||
@@ -32,7 +32,7 @@ public sealed class OpenApiEndpointTests : IClassFixture<NotifierApplicationFact
|
||||
[Fact(Explicit = true, Skip = "Pending test host wiring")]
|
||||
public async Task Deprecation_headers_emitted_for_api_surface()
|
||||
{
|
||||
var response = await _client.GetAsync("/api/v1/notify/rules", TestContext.Current.CancellationToken);
|
||||
var response = await _client.GetAsync("/api/v1/notify/rules", CancellationToken.None);
|
||||
|
||||
Assert.True(response.Headers.TryGetValues("Deprecation", out var depValues) &&
|
||||
depValues.Contains("true"));
|
||||
@@ -46,7 +46,7 @@ public sealed class OpenApiEndpointTests : IClassFixture<NotifierApplicationFact
|
||||
public async Task PackApprovals_endpoint_validates_missing_headers()
|
||||
{
|
||||
var content = new StringContent("""{"eventId":"00000000-0000-0000-0000-000000000001","issuedAt":"2025-11-17T16:00:00Z","kind":"pack.approval.granted","packId":"offline-kit","decision":"approved","actor":"task-runner"}""", Encoding.UTF8, "application/json");
|
||||
var response = await _client.PostAsync("/api/v1/notify/pack-approvals", content, TestContext.Current.CancellationToken);
|
||||
var response = await _client.PostAsync("/api/v1/notify/pack-approvals", content, CancellationToken.None);
|
||||
|
||||
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
|
||||
}
|
||||
@@ -62,7 +62,7 @@ public sealed class OpenApiEndpointTests : IClassFixture<NotifierApplicationFact
|
||||
request.Headers.Add("X-StellaOps-Tenant", "tenant-a");
|
||||
request.Headers.Add("Idempotency-Key", Guid.NewGuid().ToString());
|
||||
|
||||
var response = await _client.SendAsync(request, TestContext.Current.CancellationToken);
|
||||
var response = await _client.SendAsync(request, CancellationToken.None);
|
||||
|
||||
Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);
|
||||
Assert.True(response.Headers.TryGetValues("X-Resume-After", out var resumeValues) &&
|
||||
@@ -74,7 +74,7 @@ public sealed class OpenApiEndpointTests : IClassFixture<NotifierApplicationFact
|
||||
public async Task PackApprovals_acknowledgement_requires_tenant_and_token()
|
||||
{
|
||||
var ackContent = new StringContent("""{"ackToken":"token-123"}""", Encoding.UTF8, "application/json");
|
||||
var ackResponse = await _client.PostAsync("/api/v1/notify/pack-approvals/offline-kit/ack", ackContent, TestContext.Current.CancellationToken);
|
||||
var ackResponse = await _client.PostAsync("/api/v1/notify/pack-approvals/offline-kit/ack", ackContent, CancellationToken.None);
|
||||
Assert.Equal(HttpStatusCode.BadRequest, ackResponse.StatusCode);
|
||||
|
||||
var ackReq = new HttpRequestMessage(HttpMethod.Post, "/api/v1/notify/pack-approvals/offline-kit/ack")
|
||||
@@ -82,7 +82,7 @@ public sealed class OpenApiEndpointTests : IClassFixture<NotifierApplicationFact
|
||||
Content = ackContent
|
||||
};
|
||||
ackReq.Headers.Add("X-StellaOps-Tenant", "tenant-a");
|
||||
var goodResponse = await _client.SendAsync(ackReq, TestContext.Current.CancellationToken);
|
||||
var goodResponse = await _client.SendAsync(ackReq, CancellationToken.None);
|
||||
Assert.Equal(HttpStatusCode.NoContent, goodResponse.StatusCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,25 +23,25 @@ public sealed class PackApprovalTemplateSeederTests
|
||||
templateRepo,
|
||||
contentRoot,
|
||||
logger,
|
||||
cancellationToken: TestContext.Current.CancellationToken);
|
||||
cancellationToken: CancellationToken.None);
|
||||
var routed = await PackApprovalTemplateSeeder.SeedRoutingAsync(
|
||||
channelRepo,
|
||||
ruleRepo,
|
||||
logger,
|
||||
cancellationToken: TestContext.Current.CancellationToken);
|
||||
cancellationToken: CancellationToken.None);
|
||||
|
||||
Assert.True(count >= 2, "Expected at least two templates to be seeded.");
|
||||
Assert.Equal(3, routed);
|
||||
|
||||
var templates = await templateRepo.ListAsync("tenant-sample", TestContext.Current.CancellationToken);
|
||||
var templates = await templateRepo.ListAsync("tenant-sample", CancellationToken.None);
|
||||
Assert.Contains(templates, t => t.TemplateId == "tmpl-pack-approval-slack-en");
|
||||
Assert.Contains(templates, t => t.TemplateId == "tmpl-pack-approval-email-en");
|
||||
|
||||
var channels = await channelRepo.ListAsync("tenant-sample", cancellationToken: TestContext.Current.CancellationToken);
|
||||
var channels = await channelRepo.ListAsync("tenant-sample", cancellationToken: CancellationToken.None);
|
||||
Assert.Contains(channels, c => c.ChannelId == "chn-pack-approvals-slack");
|
||||
Assert.Contains(channels, c => c.ChannelId == "chn-pack-approvals-email");
|
||||
|
||||
var rules = await ruleRepo.ListAsync("tenant-sample", TestContext.Current.CancellationToken);
|
||||
var rules = await ruleRepo.ListAsync("tenant-sample", CancellationToken.None);
|
||||
Assert.Contains(rules, r => r.RuleId == "rule-pack-approvals-default");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json;
|
||||
using Xunit;
|
||||
|
||||
|
||||
@@ -56,7 +56,6 @@ public sealed class PackApprovalTemplateTests
|
||||
var path = LocatePackApprovalTemplatesPath();
|
||||
var json = File.ReadAllText(path);
|
||||
using var doc = JsonDocument.Parse(json);
|
||||
using StellaOps.TestKit;
|
||||
return doc.RootElement.Clone();
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ public sealed class RiskEventEndpointTests : IClassFixture<NotifierApplicationFa
|
||||
};
|
||||
message.Headers.Add("X-StellaOps-Tenant", "tenant-sample");
|
||||
|
||||
var response = await client.SendAsync(message, TestContext.Current.CancellationToken);
|
||||
var response = await client.SendAsync(message, CancellationToken.None);
|
||||
|
||||
Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);
|
||||
Assert.Single(recordingQueue.Published);
|
||||
|
||||
@@ -24,23 +24,23 @@ public sealed class RiskTemplateSeederTests
|
||||
templateRepo,
|
||||
contentRoot,
|
||||
logger,
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
|
||||
var seededRouting = await RiskTemplateSeeder.SeedRoutingAsync(
|
||||
channelRepo,
|
||||
ruleRepo,
|
||||
contentRoot,
|
||||
logger,
|
||||
TestContext.Current.CancellationToken);
|
||||
CancellationToken.None);
|
||||
|
||||
Assert.True(seededTemplates >= 4, "Expected risk templates to be seeded.");
|
||||
Assert.True(seededRouting >= 0, $"Expected risk routing seed to create channels and rules but got {seededRouting}.");
|
||||
|
||||
var templates = await templateRepo.ListAsync("bootstrap", TestContext.Current.CancellationToken);
|
||||
var templates = await templateRepo.ListAsync("bootstrap", CancellationToken.None);
|
||||
Assert.Contains(templates, t => t.Key == "tmpl-risk-severity-change");
|
||||
Assert.Contains(templates, t => t.Key == "tmpl-risk-profile-state");
|
||||
|
||||
var rules = await ruleRepo.ListAsync("bootstrap", TestContext.Current.CancellationToken);
|
||||
var rules = await ruleRepo.ListAsync("bootstrap", CancellationToken.None);
|
||||
Assert.Contains(rules, r => r.Match.EventKinds.Contains("risk.profile.severity.changed"));
|
||||
Assert.Contains(rules, r => r.Match.EventKinds.Contains("risk.profile.published"));
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public class SigningServiceTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var token = await _signingService.SignAsync(payload);
|
||||
var token = await _signingService.SignAsync(payload, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(token);
|
||||
@@ -66,10 +66,10 @@ public class SigningServiceTests
|
||||
Subject = "incident-123",
|
||||
ExpiresAt = _timeProvider.GetUtcNow().AddHours(24)
|
||||
};
|
||||
var token = await _signingService.SignAsync(payload);
|
||||
var token = await _signingService.SignAsync(payload, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _signingService.VerifyAsync(token);
|
||||
var result = await _signingService.VerifyAsync(token, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsValid);
|
||||
@@ -92,13 +92,13 @@ public class SigningServiceTests
|
||||
Subject = "incident-123",
|
||||
ExpiresAt = _timeProvider.GetUtcNow().AddHours(1)
|
||||
};
|
||||
var token = await _signingService.SignAsync(payload);
|
||||
var token = await _signingService.SignAsync(payload, CancellationToken.None);
|
||||
|
||||
// Advance time past expiry
|
||||
_timeProvider.Advance(TimeSpan.FromHours(2));
|
||||
|
||||
// Act
|
||||
var result = await _signingService.VerifyAsync(token);
|
||||
var result = await _signingService.VerifyAsync(token, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsValid);
|
||||
@@ -117,14 +117,14 @@ public class SigningServiceTests
|
||||
Subject = "incident-123",
|
||||
ExpiresAt = _timeProvider.GetUtcNow().AddHours(24)
|
||||
};
|
||||
var token = await _signingService.SignAsync(payload);
|
||||
var token = await _signingService.SignAsync(payload, CancellationToken.None);
|
||||
|
||||
// Tamper with the token
|
||||
var parts = token.Split('.');
|
||||
var tamperedToken = $"{parts[0]}.{parts[1]}.tampered_signature";
|
||||
|
||||
// Act
|
||||
var result = await _signingService.VerifyAsync(tamperedToken);
|
||||
var result = await _signingService.VerifyAsync(tamperedToken, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsValid);
|
||||
@@ -135,7 +135,7 @@ public class SigningServiceTests
|
||||
public async Task VerifyAsync_MalformedToken_ReturnsInvalidFormat()
|
||||
{
|
||||
// Act
|
||||
var result = await _signingService.VerifyAsync("not-a-valid-token");
|
||||
var result = await _signingService.VerifyAsync("not-a-valid-token", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsValid);
|
||||
@@ -154,7 +154,7 @@ public class SigningServiceTests
|
||||
Subject = "incident-123",
|
||||
ExpiresAt = _timeProvider.GetUtcNow().AddHours(24)
|
||||
};
|
||||
var token = await _signingService.SignAsync(payload);
|
||||
var token = await _signingService.SignAsync(payload, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var info = _signingService.GetTokenInfo(token);
|
||||
@@ -180,14 +180,14 @@ public class SigningServiceTests
|
||||
public async Task RotateKeyAsync_CreatesNewKey()
|
||||
{
|
||||
// Arrange
|
||||
var keysBefore = await _keyProvider.ListKeyIdsAsync();
|
||||
var keysBefore = await _keyProvider.ListKeyIdsAsync(CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var success = await _signingService.RotateKeyAsync();
|
||||
var success = await _signingService.RotateKeyAsync(CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(success);
|
||||
var keysAfter = await _keyProvider.ListKeyIdsAsync();
|
||||
var keysAfter = await _keyProvider.ListKeyIdsAsync(CancellationToken.None);
|
||||
Assert.True(keysAfter.Count > keysBefore.Count);
|
||||
}
|
||||
|
||||
@@ -210,8 +210,8 @@ public class SigningServiceTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var token = await _signingService.SignAsync(payload);
|
||||
var result = await _signingService.VerifyAsync(token);
|
||||
var token = await _signingService.SignAsync(payload, CancellationToken.None);
|
||||
var result = await _signingService.VerifyAsync(token, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsValid);
|
||||
@@ -233,13 +233,13 @@ public class SigningServiceTests
|
||||
Subject = "incident-123",
|
||||
ExpiresAt = _timeProvider.GetUtcNow().AddHours(24)
|
||||
};
|
||||
var token = await _signingService.SignAsync(payload);
|
||||
var token = await _signingService.SignAsync(payload, CancellationToken.None);
|
||||
|
||||
// Rotate key
|
||||
await _signingService.RotateKeyAsync();
|
||||
await _signingService.RotateKeyAsync(CancellationToken.None);
|
||||
|
||||
// Act - verify with new current key (but old key should still be available)
|
||||
var result = await _signingService.VerifyAsync(token);
|
||||
var result = await _signingService.VerifyAsync(token, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsValid);
|
||||
@@ -269,7 +269,7 @@ public class LocalSigningKeyProviderTests
|
||||
public async Task GetCurrentKeyAsync_ReturnsKey()
|
||||
{
|
||||
// Act
|
||||
var key = await _keyProvider.GetCurrentKeyAsync();
|
||||
var key = await _keyProvider.GetCurrentKeyAsync(CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(key);
|
||||
@@ -281,10 +281,10 @@ public class LocalSigningKeyProviderTests
|
||||
public async Task GetKeyByIdAsync_ExistingKey_ReturnsKey()
|
||||
{
|
||||
// Arrange
|
||||
var currentKey = await _keyProvider.GetCurrentKeyAsync();
|
||||
var currentKey = await _keyProvider.GetCurrentKeyAsync(CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var key = await _keyProvider.GetKeyByIdAsync(currentKey.KeyId);
|
||||
var key = await _keyProvider.GetKeyByIdAsync(currentKey.KeyId, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(key);
|
||||
@@ -295,7 +295,7 @@ public class LocalSigningKeyProviderTests
|
||||
public async Task GetKeyByIdAsync_NonExistentKey_ReturnsNull()
|
||||
{
|
||||
// Act
|
||||
var key = await _keyProvider.GetKeyByIdAsync("non-existent-key");
|
||||
var key = await _keyProvider.GetKeyByIdAsync("non-existent-key", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Null(key);
|
||||
@@ -305,16 +305,16 @@ public class LocalSigningKeyProviderTests
|
||||
public async Task RotateAsync_CreatesNewCurrentKey()
|
||||
{
|
||||
// Arrange
|
||||
var oldKey = await _keyProvider.GetCurrentKeyAsync();
|
||||
var oldKey = await _keyProvider.GetCurrentKeyAsync(CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var newKey = await _keyProvider.RotateAsync();
|
||||
var newKey = await _keyProvider.RotateAsync(CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotEqual(oldKey.KeyId, newKey.KeyId);
|
||||
Assert.True(newKey.IsCurrent);
|
||||
|
||||
var currentKey = await _keyProvider.GetCurrentKeyAsync();
|
||||
var currentKey = await _keyProvider.GetCurrentKeyAsync(CancellationToken.None);
|
||||
Assert.Equal(newKey.KeyId, currentKey.KeyId);
|
||||
}
|
||||
|
||||
@@ -322,13 +322,13 @@ public class LocalSigningKeyProviderTests
|
||||
public async Task RotateAsync_KeepsOldKeyForVerification()
|
||||
{
|
||||
// Arrange
|
||||
var oldKey = await _keyProvider.GetCurrentKeyAsync();
|
||||
var oldKey = await _keyProvider.GetCurrentKeyAsync(CancellationToken.None);
|
||||
|
||||
// Act
|
||||
await _keyProvider.RotateAsync();
|
||||
await _keyProvider.RotateAsync(CancellationToken.None);
|
||||
|
||||
// Assert - old key should still be retrievable
|
||||
var retrievedOldKey = await _keyProvider.GetKeyByIdAsync(oldKey.KeyId);
|
||||
var retrievedOldKey = await _keyProvider.GetKeyByIdAsync(oldKey.KeyId, CancellationToken.None);
|
||||
Assert.NotNull(retrievedOldKey);
|
||||
Assert.False(retrievedOldKey.IsCurrent);
|
||||
}
|
||||
@@ -337,11 +337,11 @@ public class LocalSigningKeyProviderTests
|
||||
public async Task ListKeyIdsAsync_ReturnsAllKeys()
|
||||
{
|
||||
// Arrange
|
||||
await _keyProvider.RotateAsync();
|
||||
await _keyProvider.RotateAsync();
|
||||
await _keyProvider.RotateAsync(CancellationToken.None);
|
||||
await _keyProvider.RotateAsync(CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var keyIds = await _keyProvider.ListKeyIdsAsync();
|
||||
var keyIds = await _keyProvider.ListKeyIdsAsync(CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, keyIds.Count); // Initial + 2 rotations
|
||||
|
||||
@@ -33,11 +33,10 @@ public class TenantIsolationValidatorTests
|
||||
public async Task ValidateResourceAccessAsync_SameTenant_Allowed()
|
||||
{
|
||||
// Arrange
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001");
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _validator.ValidateResourceAccessAsync(
|
||||
"tenant1", "delivery", "delivery-001", TenantAccessOperation.Read);
|
||||
var result = await _validator.ValidateResourceAccessAsync("tenant1", "delivery", "delivery-001", TenantAccessOperation.Read, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsAllowed);
|
||||
@@ -48,11 +47,10 @@ public class TenantIsolationValidatorTests
|
||||
public async Task ValidateResourceAccessAsync_DifferentTenant_Denied()
|
||||
{
|
||||
// Arrange
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001");
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _validator.ValidateResourceAccessAsync(
|
||||
"tenant2", "delivery", "delivery-001", TenantAccessOperation.Read);
|
||||
var result = await _validator.ValidateResourceAccessAsync("tenant2", "delivery", "delivery-001", TenantAccessOperation.Read, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsAllowed);
|
||||
@@ -63,11 +61,10 @@ public class TenantIsolationValidatorTests
|
||||
public async Task ValidateResourceAccessAsync_AdminTenant_AlwaysAllowed()
|
||||
{
|
||||
// Arrange
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001");
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _validator.ValidateResourceAccessAsync(
|
||||
"admin", "delivery", "delivery-001", TenantAccessOperation.Read);
|
||||
var result = await _validator.ValidateResourceAccessAsync("admin", "delivery", "delivery-001", TenantAccessOperation.Read, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsAllowed);
|
||||
@@ -78,11 +75,10 @@ public class TenantIsolationValidatorTests
|
||||
public async Task ValidateResourceAccessAsync_SystemResource_AlwaysAllowed()
|
||||
{
|
||||
// Arrange
|
||||
await _validator.RegisterResourceAsync("tenant1", "system-template", "template-001");
|
||||
await _validator.RegisterResourceAsync("tenant1", "system-template", "template-001", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _validator.ValidateResourceAccessAsync(
|
||||
"tenant2", "system-template", "template-001", TenantAccessOperation.Read);
|
||||
var result = await _validator.ValidateResourceAccessAsync("tenant2", "system-template", "template-001", TenantAccessOperation.Read, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsAllowed);
|
||||
@@ -93,8 +89,7 @@ public class TenantIsolationValidatorTests
|
||||
public async Task ValidateResourceAccessAsync_UnregisteredResource_Allowed()
|
||||
{
|
||||
// Act - resource not registered
|
||||
var result = await _validator.ValidateResourceAccessAsync(
|
||||
"tenant1", "delivery", "unregistered-delivery", TenantAccessOperation.Read);
|
||||
var result = await _validator.ValidateResourceAccessAsync("tenant1", "delivery", "unregistered-delivery", TenantAccessOperation.Read, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsAllowed);
|
||||
@@ -105,10 +100,10 @@ public class TenantIsolationValidatorTests
|
||||
public async Task ValidateDeliveryAsync_SameTenant_Allowed()
|
||||
{
|
||||
// Arrange
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001");
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _validator.ValidateDeliveryAsync("tenant1", "delivery-001");
|
||||
var result = await _validator.ValidateDeliveryAsync("tenant1", "delivery-001", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsAllowed);
|
||||
@@ -118,10 +113,10 @@ public class TenantIsolationValidatorTests
|
||||
public async Task ValidateChannelAsync_SameTenant_Allowed()
|
||||
{
|
||||
// Arrange
|
||||
await _validator.RegisterResourceAsync("tenant1", "channel", "channel-001");
|
||||
await _validator.RegisterResourceAsync("tenant1", "channel", "channel-001", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _validator.ValidateChannelAsync("tenant1", "channel-001");
|
||||
var result = await _validator.ValidateChannelAsync("tenant1", "channel-001", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsAllowed);
|
||||
@@ -131,10 +126,10 @@ public class TenantIsolationValidatorTests
|
||||
public async Task ValidateTemplateAsync_SameTenant_Allowed()
|
||||
{
|
||||
// Arrange
|
||||
await _validator.RegisterResourceAsync("tenant1", "template", "template-001");
|
||||
await _validator.RegisterResourceAsync("tenant1", "template", "template-001", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _validator.ValidateTemplateAsync("tenant1", "template-001");
|
||||
var result = await _validator.ValidateTemplateAsync("tenant1", "template-001", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsAllowed);
|
||||
@@ -144,10 +139,10 @@ public class TenantIsolationValidatorTests
|
||||
public async Task ValidateSubscriptionAsync_SameTenant_Allowed()
|
||||
{
|
||||
// Arrange
|
||||
await _validator.RegisterResourceAsync("tenant1", "subscription", "subscription-001");
|
||||
await _validator.RegisterResourceAsync("tenant1", "subscription", "subscription-001", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _validator.ValidateSubscriptionAsync("tenant1", "subscription-001");
|
||||
var result = await _validator.ValidateSubscriptionAsync("tenant1", "subscription-001", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsAllowed);
|
||||
@@ -157,15 +152,12 @@ public class TenantIsolationValidatorTests
|
||||
public async Task GrantCrossTenantAccessAsync_EnablesAccess()
|
||||
{
|
||||
// Arrange
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001");
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
await _validator.GrantCrossTenantAccessAsync(
|
||||
"tenant1", "tenant2", "delivery", "delivery-001",
|
||||
TenantAccessOperation.Read, null, "admin");
|
||||
await _validator.GrantCrossTenantAccessAsync("tenant1", "tenant2", "delivery", "delivery-001", TenantAccessOperation.Read, null, "admin", CancellationToken.None);
|
||||
|
||||
var result = await _validator.ValidateResourceAccessAsync(
|
||||
"tenant2", "delivery", "delivery-001", TenantAccessOperation.Read);
|
||||
var result = await _validator.ValidateResourceAccessAsync("tenant2", "delivery", "delivery-001", TenantAccessOperation.Read, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsAllowed);
|
||||
@@ -177,17 +169,13 @@ public class TenantIsolationValidatorTests
|
||||
public async Task RevokeCrossTenantAccessAsync_DisablesAccess()
|
||||
{
|
||||
// Arrange
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001");
|
||||
await _validator.GrantCrossTenantAccessAsync(
|
||||
"tenant1", "tenant2", "delivery", "delivery-001",
|
||||
TenantAccessOperation.Read, null, "admin");
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001", CancellationToken.None);
|
||||
await _validator.GrantCrossTenantAccessAsync("tenant1", "tenant2", "delivery", "delivery-001", TenantAccessOperation.Read, null, "admin", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
await _validator.RevokeCrossTenantAccessAsync(
|
||||
"tenant1", "tenant2", "delivery", "delivery-001", "admin");
|
||||
await _validator.RevokeCrossTenantAccessAsync("tenant1", "tenant2", "delivery", "delivery-001", "admin", CancellationToken.None);
|
||||
|
||||
var result = await _validator.ValidateResourceAccessAsync(
|
||||
"tenant2", "delivery", "delivery-001", TenantAccessOperation.Read);
|
||||
var result = await _validator.ValidateResourceAccessAsync("tenant2", "delivery", "delivery-001", TenantAccessOperation.Read, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsAllowed);
|
||||
@@ -197,24 +185,20 @@ public class TenantIsolationValidatorTests
|
||||
public async Task GrantCrossTenantAccessAsync_WithExpiry_ExpiresCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001");
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001", CancellationToken.None);
|
||||
var expiresAt = _timeProvider.GetUtcNow().AddHours(1);
|
||||
|
||||
await _validator.GrantCrossTenantAccessAsync(
|
||||
"tenant1", "tenant2", "delivery", "delivery-001",
|
||||
TenantAccessOperation.Read, expiresAt, "admin");
|
||||
await _validator.GrantCrossTenantAccessAsync("tenant1", "tenant2", "delivery", "delivery-001", TenantAccessOperation.Read, expiresAt, "admin", CancellationToken.None);
|
||||
|
||||
// Verify access before expiry
|
||||
var resultBefore = await _validator.ValidateResourceAccessAsync(
|
||||
"tenant2", "delivery", "delivery-001", TenantAccessOperation.Read);
|
||||
var resultBefore = await _validator.ValidateResourceAccessAsync("tenant2", "delivery", "delivery-001", TenantAccessOperation.Read, CancellationToken.None);
|
||||
Assert.True(resultBefore.IsAllowed);
|
||||
|
||||
// Advance time past expiry
|
||||
_timeProvider.Advance(TimeSpan.FromHours(2));
|
||||
|
||||
// Act
|
||||
var resultAfter = await _validator.ValidateResourceAccessAsync(
|
||||
"tenant2", "delivery", "delivery-001", TenantAccessOperation.Read);
|
||||
var resultAfter = await _validator.ValidateResourceAccessAsync("tenant2", "delivery", "delivery-001", TenantAccessOperation.Read, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(resultAfter.IsAllowed);
|
||||
@@ -224,18 +208,14 @@ public class TenantIsolationValidatorTests
|
||||
public async Task GrantCrossTenantAccessAsync_OperationRestrictions_Enforced()
|
||||
{
|
||||
// Arrange
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001");
|
||||
await _validator.GrantCrossTenantAccessAsync(
|
||||
"tenant1", "tenant2", "delivery", "delivery-001",
|
||||
TenantAccessOperation.Read, null, "admin");
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001", CancellationToken.None);
|
||||
await _validator.GrantCrossTenantAccessAsync("tenant1", "tenant2", "delivery", "delivery-001", TenantAccessOperation.Read, null, "admin", CancellationToken.None);
|
||||
|
||||
// Act - Read should be allowed
|
||||
var readResult = await _validator.ValidateResourceAccessAsync(
|
||||
"tenant2", "delivery", "delivery-001", TenantAccessOperation.Read);
|
||||
var readResult = await _validator.ValidateResourceAccessAsync("tenant2", "delivery", "delivery-001", TenantAccessOperation.Read, CancellationToken.None);
|
||||
|
||||
// Write should be denied (not in granted operations)
|
||||
var writeResult = await _validator.ValidateResourceAccessAsync(
|
||||
"tenant2", "delivery", "delivery-001", TenantAccessOperation.Write);
|
||||
var writeResult = await _validator.ValidateResourceAccessAsync("tenant2", "delivery", "delivery-001", TenantAccessOperation.Write, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(readResult.IsAllowed);
|
||||
@@ -246,14 +226,13 @@ public class TenantIsolationValidatorTests
|
||||
public async Task GetViolationsAsync_ReturnsRecordedViolations()
|
||||
{
|
||||
// Arrange
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001");
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001", CancellationToken.None);
|
||||
|
||||
// Trigger a violation
|
||||
await _validator.ValidateResourceAccessAsync(
|
||||
"tenant2", "delivery", "delivery-001", TenantAccessOperation.Read);
|
||||
await _validator.ValidateResourceAccessAsync("tenant2", "delivery", "delivery-001", TenantAccessOperation.Read, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var violations = await _validator.GetViolationsAsync("tenant2");
|
||||
var violations = await _validator.GetViolationsAsync("tenant2", cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Single(violations);
|
||||
@@ -265,19 +244,17 @@ public class TenantIsolationValidatorTests
|
||||
public async Task GetViolationsAsync_FiltersBySince()
|
||||
{
|
||||
// Arrange
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001");
|
||||
await _validator.ValidateResourceAccessAsync(
|
||||
"tenant2", "delivery", "delivery-001", TenantAccessOperation.Read);
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001", CancellationToken.None);
|
||||
await _validator.ValidateResourceAccessAsync("tenant2", "delivery", "delivery-001", TenantAccessOperation.Read, CancellationToken.None);
|
||||
|
||||
_timeProvider.Advance(TimeSpan.FromHours(2));
|
||||
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-002");
|
||||
await _validator.ValidateResourceAccessAsync(
|
||||
"tenant2", "delivery", "delivery-002", TenantAccessOperation.Read);
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-002", CancellationToken.None);
|
||||
await _validator.ValidateResourceAccessAsync("tenant2", "delivery", "delivery-002", TenantAccessOperation.Read, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var since = _timeProvider.GetUtcNow().AddHours(-1);
|
||||
var violations = await _validator.GetViolationsAsync(null, since);
|
||||
var violations = await _validator.GetViolationsAsync(null, since, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Single(violations);
|
||||
@@ -288,8 +265,8 @@ public class TenantIsolationValidatorTests
|
||||
public async Task RegisterResourceAsync_AddsResource()
|
||||
{
|
||||
// Act
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001");
|
||||
var resources = await _validator.GetTenantResourcesAsync("tenant1");
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001", CancellationToken.None);
|
||||
var resources = await _validator.GetTenantResourcesAsync("tenant1", cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Single(resources);
|
||||
@@ -302,11 +279,11 @@ public class TenantIsolationValidatorTests
|
||||
public async Task UnregisterResourceAsync_RemovesResource()
|
||||
{
|
||||
// Arrange
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001");
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
await _validator.UnregisterResourceAsync("delivery", "delivery-001");
|
||||
var resources = await _validator.GetTenantResourcesAsync("tenant1");
|
||||
await _validator.UnregisterResourceAsync("delivery", "delivery-001", CancellationToken.None);
|
||||
var resources = await _validator.GetTenantResourcesAsync("tenant1", cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Empty(resources);
|
||||
@@ -316,11 +293,11 @@ public class TenantIsolationValidatorTests
|
||||
public async Task GetTenantResourcesAsync_FiltersByResourceType()
|
||||
{
|
||||
// Arrange
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001");
|
||||
await _validator.RegisterResourceAsync("tenant1", "channel", "channel-001");
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001", CancellationToken.None);
|
||||
await _validator.RegisterResourceAsync("tenant1", "channel", "channel-001", CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var deliveries = await _validator.GetTenantResourcesAsync("tenant1", "delivery");
|
||||
var deliveries = await _validator.GetTenantResourcesAsync("tenant1", "delivery", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Single(deliveries);
|
||||
@@ -342,7 +319,7 @@ public class TenantIsolationValidatorTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _validator.RunFuzzTestAsync(config);
|
||||
var result = await _validator.RunFuzzTestAsync(config, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.AllPassed);
|
||||
@@ -355,8 +332,7 @@ public class TenantIsolationValidatorTests
|
||||
public async Task ValidateCrossTenantAccessAsync_SameTenant_Allowed()
|
||||
{
|
||||
// Act
|
||||
var result = await _validator.ValidateCrossTenantAccessAsync(
|
||||
"tenant1", "tenant1", "delivery", "delivery-001");
|
||||
var result = await _validator.ValidateCrossTenantAccessAsync("tenant1", "tenant1", "delivery", "delivery-001", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsAllowed);
|
||||
@@ -367,18 +343,16 @@ public class TenantIsolationValidatorTests
|
||||
public async Task ViolationSeverity_ReflectsOperation()
|
||||
{
|
||||
// Arrange
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001");
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-001", CancellationToken.None);
|
||||
|
||||
// Trigger different violations
|
||||
await _validator.ValidateResourceAccessAsync(
|
||||
"tenant2", "delivery", "delivery-001", TenantAccessOperation.Read);
|
||||
await _validator.ValidateResourceAccessAsync("tenant2", "delivery", "delivery-001", TenantAccessOperation.Read, CancellationToken.None);
|
||||
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-002");
|
||||
await _validator.ValidateResourceAccessAsync(
|
||||
"tenant2", "delivery", "delivery-002", TenantAccessOperation.Delete);
|
||||
await _validator.RegisterResourceAsync("tenant1", "delivery", "delivery-002", CancellationToken.None);
|
||||
await _validator.ValidateResourceAccessAsync("tenant2", "delivery", "delivery-002", TenantAccessOperation.Delete, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var violations = await _validator.GetViolationsAsync("tenant2");
|
||||
var violations = await _validator.GetViolationsAsync("tenant2", cancellationToken: CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var readViolation = violations.FirstOrDefault(v => v.ResourceId == "delivery-001");
|
||||
|
||||
@@ -38,7 +38,7 @@ public class WebhookSecurityServiceTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _webhookService.ValidateAsync(request);
|
||||
var result = await _webhookService.ValidateAsync(request, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsValid);
|
||||
@@ -58,7 +58,7 @@ public class WebhookSecurityServiceTests
|
||||
Algorithm = "SHA256",
|
||||
RequireSignature = true
|
||||
};
|
||||
await _webhookService.RegisterWebhookAsync(config);
|
||||
await _webhookService.RegisterWebhookAsync(config, CancellationToken.None);
|
||||
|
||||
var body = "{\"test\": \"data\"}";
|
||||
var signature = _webhookService.GenerateSignature(body, config.SecretKey);
|
||||
@@ -72,7 +72,7 @@ public class WebhookSecurityServiceTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _webhookService.ValidateAsync(request);
|
||||
var result = await _webhookService.ValidateAsync(request, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsValid);
|
||||
@@ -91,7 +91,7 @@ public class WebhookSecurityServiceTests
|
||||
SecretKey = "test-secret-key",
|
||||
RequireSignature = true
|
||||
};
|
||||
await _webhookService.RegisterWebhookAsync(config);
|
||||
await _webhookService.RegisterWebhookAsync(config, CancellationToken.None);
|
||||
|
||||
var request = new WebhookValidationRequest
|
||||
{
|
||||
@@ -102,7 +102,7 @@ public class WebhookSecurityServiceTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _webhookService.ValidateAsync(request);
|
||||
var result = await _webhookService.ValidateAsync(request, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsValid);
|
||||
@@ -121,7 +121,7 @@ public class WebhookSecurityServiceTests
|
||||
SecretKey = "test-secret-key",
|
||||
RequireSignature = true
|
||||
};
|
||||
await _webhookService.RegisterWebhookAsync(config);
|
||||
await _webhookService.RegisterWebhookAsync(config, CancellationToken.None);
|
||||
|
||||
var request = new WebhookValidationRequest
|
||||
{
|
||||
@@ -131,7 +131,7 @@ public class WebhookSecurityServiceTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _webhookService.ValidateAsync(request);
|
||||
var result = await _webhookService.ValidateAsync(request, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsValid);
|
||||
@@ -152,7 +152,7 @@ public class WebhookSecurityServiceTests
|
||||
EnforceIpAllowlist = true,
|
||||
AllowedIps = ["192.168.1.0/24"]
|
||||
};
|
||||
await _webhookService.RegisterWebhookAsync(config);
|
||||
await _webhookService.RegisterWebhookAsync(config, CancellationToken.None);
|
||||
|
||||
var request = new WebhookValidationRequest
|
||||
{
|
||||
@@ -163,7 +163,7 @@ public class WebhookSecurityServiceTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _webhookService.ValidateAsync(request);
|
||||
var result = await _webhookService.ValidateAsync(request, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsValid);
|
||||
@@ -184,7 +184,7 @@ public class WebhookSecurityServiceTests
|
||||
EnforceIpAllowlist = true,
|
||||
AllowedIps = ["192.168.1.0/24"]
|
||||
};
|
||||
await _webhookService.RegisterWebhookAsync(config);
|
||||
await _webhookService.RegisterWebhookAsync(config, CancellationToken.None);
|
||||
|
||||
var request = new WebhookValidationRequest
|
||||
{
|
||||
@@ -195,7 +195,7 @@ public class WebhookSecurityServiceTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _webhookService.ValidateAsync(request);
|
||||
var result = await _webhookService.ValidateAsync(request, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsValid);
|
||||
@@ -215,7 +215,7 @@ public class WebhookSecurityServiceTests
|
||||
RequireSignature = false,
|
||||
MaxRequestAge = TimeSpan.FromMinutes(5)
|
||||
};
|
||||
await _webhookService.RegisterWebhookAsync(config);
|
||||
await _webhookService.RegisterWebhookAsync(config, CancellationToken.None);
|
||||
|
||||
var request = new WebhookValidationRequest
|
||||
{
|
||||
@@ -226,7 +226,7 @@ public class WebhookSecurityServiceTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _webhookService.ValidateAsync(request);
|
||||
var result = await _webhookService.ValidateAsync(request, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.IsValid);
|
||||
@@ -245,7 +245,7 @@ public class WebhookSecurityServiceTests
|
||||
SecretKey = "test-secret-key",
|
||||
RequireSignature = true
|
||||
};
|
||||
await _webhookService.RegisterWebhookAsync(config);
|
||||
await _webhookService.RegisterWebhookAsync(config, CancellationToken.None);
|
||||
|
||||
var body = "{\"test\": \"data\"}";
|
||||
var signature = _webhookService.GenerateSignature(body, config.SecretKey);
|
||||
@@ -260,11 +260,11 @@ public class WebhookSecurityServiceTests
|
||||
};
|
||||
|
||||
// First request should succeed
|
||||
var result1 = await _webhookService.ValidateAsync(request);
|
||||
var result1 = await _webhookService.ValidateAsync(request, CancellationToken.None);
|
||||
Assert.True(result1.IsValid);
|
||||
|
||||
// Act - second request with same signature should fail
|
||||
var result2 = await _webhookService.ValidateAsync(request);
|
||||
var result2 = await _webhookService.ValidateAsync(request, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result2.IsValid);
|
||||
@@ -299,14 +299,13 @@ public class WebhookSecurityServiceTests
|
||||
EnforceIpAllowlist = true,
|
||||
AllowedIps = ["192.168.1.0/24"]
|
||||
};
|
||||
await _webhookService.RegisterWebhookAsync(config);
|
||||
await _webhookService.RegisterWebhookAsync(config, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
await _webhookService.UpdateAllowlistAsync(
|
||||
"tenant1", "channel1", ["10.0.0.0/8"], "admin");
|
||||
await _webhookService.UpdateAllowlistAsync("tenant1", "channel1", ["10.0.0.0/8"], "admin", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
var updatedConfig = await _webhookService.GetConfigAsync("tenant1", "channel1");
|
||||
var updatedConfig = await _webhookService.GetConfigAsync("tenant1", "channel1", CancellationToken.None);
|
||||
Assert.NotNull(updatedConfig);
|
||||
Assert.Single(updatedConfig.AllowedIps);
|
||||
Assert.Equal("10.0.0.0/8", updatedConfig.AllowedIps[0]);
|
||||
@@ -316,7 +315,7 @@ public class WebhookSecurityServiceTests
|
||||
public async Task IsIpAllowedAsync_NoConfig_ReturnsTrue()
|
||||
{
|
||||
// Act
|
||||
var allowed = await _webhookService.IsIpAllowedAsync("tenant1", "channel1", "192.168.1.1");
|
||||
var allowed = await _webhookService.IsIpAllowedAsync("tenant1", "channel1", "192.168.1.1", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(allowed);
|
||||
@@ -335,10 +334,10 @@ public class WebhookSecurityServiceTests
|
||||
EnforceIpAllowlist = true,
|
||||
AllowedIps = ["192.168.1.0/24"]
|
||||
};
|
||||
await _webhookService.RegisterWebhookAsync(config);
|
||||
await _webhookService.RegisterWebhookAsync(config, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var allowed = await _webhookService.IsIpAllowedAsync("tenant1", "channel1", "192.168.1.50");
|
||||
var allowed = await _webhookService.IsIpAllowedAsync("tenant1", "channel1", "192.168.1.50", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(allowed);
|
||||
@@ -357,10 +356,10 @@ public class WebhookSecurityServiceTests
|
||||
EnforceIpAllowlist = true,
|
||||
AllowedIps = ["192.168.1.100"]
|
||||
};
|
||||
await _webhookService.RegisterWebhookAsync(config);
|
||||
await _webhookService.RegisterWebhookAsync(config, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var allowed = await _webhookService.IsIpAllowedAsync("tenant1", "channel1", "192.168.1.100");
|
||||
var allowed = await _webhookService.IsIpAllowedAsync("tenant1", "channel1", "192.168.1.100", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(allowed);
|
||||
|
||||
@@ -64,7 +64,7 @@ public class SimulationEngineTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _engine.SimulateAsync(request);
|
||||
var result = await _engine.SimulateAsync(request, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
@@ -98,7 +98,7 @@ public class SimulationEngineTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _engine.SimulateAsync(request);
|
||||
var result = await _engine.SimulateAsync(request, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
@@ -130,14 +130,15 @@ public class SimulationEngineTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _engine.SimulateAsync(request);
|
||||
var result = await _engine.SimulateAsync(request, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
Assert.Single(result.EventResults);
|
||||
Assert.NotNull(result.EventResults[0].NonMatchedRules);
|
||||
Assert.Single(result.EventResults[0].NonMatchedRules);
|
||||
Assert.Equal("severity_below_threshold", result.EventResults[0].NonMatchedRules[0].Reason);
|
||||
var nonMatchedRules = result.EventResults[0].NonMatchedRules!;
|
||||
Assert.Single(nonMatchedRules);
|
||||
Assert.Equal("severity_below_threshold", nonMatchedRules[0].Reason);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -164,7 +165,7 @@ public class SimulationEngineTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _engine.SimulateAsync(request);
|
||||
var result = await _engine.SimulateAsync(request, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, result.TotalRules);
|
||||
@@ -188,7 +189,7 @@ public class SimulationEngineTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _engine.SimulateAsync(request);
|
||||
var result = await _engine.SimulateAsync(request, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
@@ -213,7 +214,7 @@ public class SimulationEngineTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _engine.SimulateAsync(request);
|
||||
var result = await _engine.SimulateAsync(request, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
@@ -264,7 +265,7 @@ public class SimulationEngineTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _engine.SimulateAsync(request);
|
||||
var result = await _engine.SimulateAsync(request, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, result.RuleSummaries.Count);
|
||||
@@ -305,7 +306,7 @@ public class SimulationEngineTests
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = await _engine.SimulateAsync(request);
|
||||
var result = await _engine.SimulateAsync(request, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(1, result.TotalRules);
|
||||
@@ -318,7 +319,7 @@ public class SimulationEngineTests
|
||||
var rule = CreateTestRule("valid-rule");
|
||||
|
||||
// Act
|
||||
var result = await _engine.ValidateRuleAsync(rule);
|
||||
var result = await _engine.ValidateRuleAsync(rule, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsValid);
|
||||
@@ -338,7 +339,7 @@ public class SimulationEngineTests
|
||||
enabled: true);
|
||||
|
||||
// Act
|
||||
var result = await _engine.ValidateRuleAsync(rule);
|
||||
var result = await _engine.ValidateRuleAsync(rule, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsValid);
|
||||
@@ -352,7 +353,7 @@ public class SimulationEngineTests
|
||||
var rule = CreateTestRule("disabled-rule", enabled: false);
|
||||
|
||||
// Act
|
||||
var result = await _engine.ValidateRuleAsync(rule);
|
||||
var result = await _engine.ValidateRuleAsync(rule, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsValid);
|
||||
@@ -372,7 +373,7 @@ public class SimulationEngineTests
|
||||
enabled: true);
|
||||
|
||||
// Act
|
||||
var result = await _engine.ValidateRuleAsync(rule);
|
||||
var result = await _engine.ValidateRuleAsync(rule, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsValid);
|
||||
@@ -392,7 +393,7 @@ public class SimulationEngineTests
|
||||
enabled: true);
|
||||
|
||||
// Act
|
||||
var result = await _engine.ValidateRuleAsync(rule);
|
||||
var result = await _engine.ValidateRuleAsync(rule, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.IsValid);
|
||||
|
||||
@@ -1,27 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<UseXunitV3>true</UseXunitV3>
|
||||
<OutputType>Exe</OutputType>
|
||||
<IsPackable>false</IsPackable>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseConcelierTestInfra>false</UseConcelierTestInfra>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.TimeProvider.Testing" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="FluentAssertions" Version="7.0.0" />
|
||||
<PackageReference Include="Moq" Version="4.20.72" />
|
||||
<PackageReference Include="xunit.v3" Version="3.0.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.3" />
|
||||
</ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" />
|
||||
<PackageReference Include="FluentAssertions" />
|
||||
<PackageReference Include="Microsoft.Extensions.TimeProvider.Testing" />
|
||||
<PackageReference Include="Moq" />
|
||||
<PackageReference Include="xunit.v3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="OpenApiEndpointTests.cs" />
|
||||
@@ -41,4 +38,4 @@
|
||||
<ProjectReference Include="..\..\..\Notify\__Libraries\StellaOps.Notify.Queue\StellaOps.Notify.Queue.csproj" />
|
||||
<ProjectReference Include="../../../__Libraries/StellaOps.TestKit/StellaOps.TestKit.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -34,7 +34,7 @@ public sealed class EnhancedTemplateRendererTests
|
||||
var notifyEvent = CreateEvent("pack.approval", "test-user");
|
||||
|
||||
// Act
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Contains("Hello test-user", result.Body);
|
||||
@@ -57,7 +57,7 @@ public sealed class EnhancedTemplateRendererTests
|
||||
var notifyEvent = CreateEvent("pack.approval", "user", payload);
|
||||
|
||||
// Act
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Pack pkg-001 version 1.2.3", result.Body);
|
||||
@@ -75,7 +75,7 @@ public sealed class EnhancedTemplateRendererTests
|
||||
var notifyEvent = CreateEvent("test.event", "user", payload);
|
||||
|
||||
// Act
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Items: [a][b][c]", result.Body);
|
||||
@@ -97,7 +97,7 @@ public sealed class EnhancedTemplateRendererTests
|
||||
var notifyEvent = CreateEvent("scan.complete", "scanner", payload);
|
||||
|
||||
// Act
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("CVE-001: high CVE-002: low ", result.Body);
|
||||
@@ -124,7 +124,7 @@ public sealed class EnhancedTemplateRendererTests
|
||||
var notifyEvent = CreateEvent("test.event", "user", payload);
|
||||
|
||||
// Act
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Contains("[REDACTED]", result.Body);
|
||||
@@ -153,7 +153,7 @@ public sealed class EnhancedTemplateRendererTests
|
||||
var notifyEvent = CreateEvent("test.event", "user", payload);
|
||||
|
||||
// Act
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Contains("Name: John", result.Body);
|
||||
@@ -168,7 +168,7 @@ public sealed class EnhancedTemplateRendererTests
|
||||
var notifyEvent = CreateEvent("test.event", "user");
|
||||
|
||||
// Act
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Contains("https://stellaops.local/notify/events/", result.Body);
|
||||
@@ -183,7 +183,7 @@ public sealed class EnhancedTemplateRendererTests
|
||||
var notifyEvent = CreateEvent("test.event", "user", payload);
|
||||
|
||||
// Act
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Contains("Upper: TEST", result.Body);
|
||||
@@ -199,7 +199,7 @@ public sealed class EnhancedTemplateRendererTests
|
||||
var notifyEvent = CreateEvent("test.event", "user", payload);
|
||||
|
||||
// Act
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.DoesNotContain("<script>", result.Body);
|
||||
@@ -218,7 +218,7 @@ public sealed class EnhancedTemplateRendererTests
|
||||
var notifyEvent = CreateEvent("security.alert", "scanner");
|
||||
|
||||
// Act
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result.Subject);
|
||||
@@ -234,8 +234,8 @@ public sealed class EnhancedTemplateRendererTests
|
||||
var notifyEvent = CreateEvent("test.event", "user");
|
||||
|
||||
// Act
|
||||
var result1 = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result2 = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result1 = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
var result2 = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result1.BodyHash);
|
||||
@@ -260,7 +260,7 @@ public sealed class EnhancedTemplateRendererTests
|
||||
var notifyEvent = CreateEvent("test.event", "user");
|
||||
|
||||
// Act
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent);
|
||||
var result = await _renderer.RenderAsync(template, notifyEvent, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Contains("<h1>", result.Body);
|
||||
@@ -279,8 +279,8 @@ public sealed class EnhancedTemplateRendererTests
|
||||
var eventFalse = CreateEvent("test", "user", payloadFalse);
|
||||
|
||||
// Act
|
||||
var resultTrue = await _renderer.RenderAsync(template, eventTrue);
|
||||
var resultFalse = await _renderer.RenderAsync(template, eventFalse);
|
||||
var resultTrue = await _renderer.RenderAsync(template, eventTrue, CancellationToken.None);
|
||||
var resultFalse = await _renderer.RenderAsync(template, eventFalse, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Contains("CRITICAL:", resultTrue.Body);
|
||||
|
||||
@@ -27,11 +27,10 @@ public sealed class NotifyTemplateServiceTests
|
||||
{
|
||||
// Arrange
|
||||
var template = CreateTemplate("tmpl-001", "pack.approval", "en-us");
|
||||
await _templateRepository.UpsertAsync(template);
|
||||
await _templateRepository.UpsertAsync(template, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var result = await _service.ResolveAsync(
|
||||
"test-tenant", "pack.approval", NotifyChannelType.Webhook, "en-US");
|
||||
var result = await _service.ResolveAsync("test-tenant", "pack.approval", NotifyChannelType.Webhook, "en-US", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
@@ -43,11 +42,10 @@ public sealed class NotifyTemplateServiceTests
|
||||
{
|
||||
// Arrange
|
||||
var template = CreateTemplate("tmpl-en", "pack.approval", "en");
|
||||
await _templateRepository.UpsertAsync(template);
|
||||
await _templateRepository.UpsertAsync(template, CancellationToken.None);
|
||||
|
||||
// Act - request en-GB but only en exists
|
||||
var result = await _service.ResolveAsync(
|
||||
"test-tenant", "pack.approval", NotifyChannelType.Webhook, "en-GB");
|
||||
var result = await _service.ResolveAsync("test-tenant", "pack.approval", NotifyChannelType.Webhook, "en-GB", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
@@ -59,11 +57,10 @@ public sealed class NotifyTemplateServiceTests
|
||||
{
|
||||
// Arrange
|
||||
var template = CreateTemplate("tmpl-default", "pack.approval", "en-us");
|
||||
await _templateRepository.UpsertAsync(template);
|
||||
await _templateRepository.UpsertAsync(template, CancellationToken.None);
|
||||
|
||||
// Act - request de-DE but only en-us exists (default)
|
||||
var result = await _service.ResolveAsync(
|
||||
"test-tenant", "pack.approval", NotifyChannelType.Webhook, "de-DE");
|
||||
var result = await _service.ResolveAsync("test-tenant", "pack.approval", NotifyChannelType.Webhook, "de-DE", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(result);
|
||||
@@ -74,8 +71,7 @@ public sealed class NotifyTemplateServiceTests
|
||||
public async Task ResolveAsync_NoMatch_ReturnsNull()
|
||||
{
|
||||
// Act
|
||||
var result = await _service.ResolveAsync(
|
||||
"test-tenant", "nonexistent.key", NotifyChannelType.Webhook, "en-US");
|
||||
var result = await _service.ResolveAsync("test-tenant", "nonexistent.key", NotifyChannelType.Webhook, "en-US", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
@@ -88,7 +84,7 @@ public sealed class NotifyTemplateServiceTests
|
||||
var template = CreateTemplate("tmpl-new", "pack.approval", "en-us");
|
||||
|
||||
// Act
|
||||
var result = await _service.UpsertAsync(template, "test-actor");
|
||||
var result = await _service.UpsertAsync(template, "test-actor", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Success);
|
||||
@@ -112,12 +108,12 @@ public sealed class NotifyTemplateServiceTests
|
||||
NullLogger<NotifyTemplateService>.Instance);
|
||||
|
||||
var original = CreateTemplate("tmpl-existing", "pack.approval", "en-us", "Original body");
|
||||
await templateRepository.UpsertAsync(original);
|
||||
await templateRepository.UpsertAsync(original, CancellationToken.None);
|
||||
|
||||
var updated = CreateTemplate("tmpl-existing", "pack.approval", "en-us", "Updated body");
|
||||
|
||||
// Act
|
||||
var result = await service.UpsertAsync(updated, "another-actor");
|
||||
var result = await service.UpsertAsync(updated, "another-actor", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(result.Success);
|
||||
@@ -141,7 +137,7 @@ public sealed class NotifyTemplateServiceTests
|
||||
body: "Hello {{name} - missing closing brace");
|
||||
|
||||
// Act
|
||||
var result = await _service.UpsertAsync(template, "test-actor");
|
||||
var result = await _service.UpsertAsync(template, "test-actor", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(result.Success);
|
||||
@@ -153,14 +149,14 @@ public sealed class NotifyTemplateServiceTests
|
||||
{
|
||||
// Arrange
|
||||
var template = CreateTemplate("tmpl-delete", "pack.approval", "en-us");
|
||||
await _templateRepository.UpsertAsync(template);
|
||||
await _templateRepository.UpsertAsync(template, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var deleted = await _service.DeleteAsync("test-tenant", "tmpl-delete", "delete-actor");
|
||||
var deleted = await _service.DeleteAsync("test-tenant", "tmpl-delete", "delete-actor", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.True(deleted);
|
||||
Assert.Null(await _templateRepository.GetAsync("test-tenant", "tmpl-delete"));
|
||||
Assert.Null(await _templateRepository.GetAsync("test-tenant", "tmpl-delete", CancellationToken.None));
|
||||
|
||||
var audit = _auditRepository.Entries.Last();
|
||||
Assert.Equal("template.deleted", audit.Action);
|
||||
@@ -170,7 +166,7 @@ public sealed class NotifyTemplateServiceTests
|
||||
public async Task DeleteAsync_NonexistentTemplate_ReturnsFalse()
|
||||
{
|
||||
// Act
|
||||
var deleted = await _service.DeleteAsync("test-tenant", "nonexistent", "actor");
|
||||
var deleted = await _service.DeleteAsync("test-tenant", "nonexistent", "actor", CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.False(deleted);
|
||||
@@ -180,16 +176,16 @@ public sealed class NotifyTemplateServiceTests
|
||||
public async Task ListAsync_WithFilters_ReturnsFilteredResults()
|
||||
{
|
||||
// Arrange
|
||||
await _templateRepository.UpsertAsync(CreateTemplate("tmpl-1", "pack.approval", "en-us"));
|
||||
await _templateRepository.UpsertAsync(CreateTemplate("tmpl-2", "pack.approval", "de-de"));
|
||||
await _templateRepository.UpsertAsync(CreateTemplate("tmpl-3", "risk.alert", "en-us"));
|
||||
await _templateRepository.UpsertAsync(CreateTemplate("tmpl-1", "pack.approval", "en-us"), CancellationToken.None);
|
||||
await _templateRepository.UpsertAsync(CreateTemplate("tmpl-2", "pack.approval", "de-de"), CancellationToken.None);
|
||||
await _templateRepository.UpsertAsync(CreateTemplate("tmpl-3", "risk.alert", "en-us"), CancellationToken.None);
|
||||
|
||||
// Act
|
||||
var results = await _service.ListAsync("test-tenant", new TemplateListOptions
|
||||
{
|
||||
KeyPrefix = "pack.",
|
||||
Locale = "en-us"
|
||||
});
|
||||
}, CancellationToken.None);
|
||||
|
||||
// Assert
|
||||
Assert.Single(results);
|
||||
|
||||
@@ -43,13 +43,13 @@ public sealed class TenantNotificationEnricherTests
|
||||
var result = enricher.Enrich(payload);
|
||||
|
||||
// Assert
|
||||
result.Should().ContainKey("_tenant");
|
||||
result.ContainsKey("_tenant").Should().BeTrue();
|
||||
var tenant = result["_tenant"]!.AsObject();
|
||||
tenant["id"]!.GetValue<string>().Should().Be("tenant-123");
|
||||
tenant["actor"]!.GetValue<string>().Should().Be("user@test.com");
|
||||
tenant["correlationId"]!.GetValue<string>().Should().Be("corr-456");
|
||||
tenant["source"]!.GetValue<string>().Should().Be("HttpHeader");
|
||||
tenant.Should().ContainKey("timestamp");
|
||||
tenant.ContainsKey("timestamp").Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -68,7 +68,7 @@ public sealed class TenantNotificationEnricherTests
|
||||
var result = enricher.Enrich(payload);
|
||||
|
||||
// Assert
|
||||
result.Should().NotContainKey("_tenant");
|
||||
result.ContainsKey("_tenant").Should().BeFalse();
|
||||
result["eventType"]!.GetValue<string>().Should().Be("test.event");
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ public sealed class TenantNotificationEnricherTests
|
||||
var result = enricher.Enrich(payload);
|
||||
|
||||
// Assert
|
||||
result.Should().NotContainKey("_tenant");
|
||||
result.ContainsKey("_tenant").Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -105,8 +105,8 @@ public sealed class TenantNotificationEnricherTests
|
||||
var result = enricher.Enrich(payload);
|
||||
|
||||
// Assert
|
||||
result.Should().ContainKey("tenantContext");
|
||||
result.Should().NotContainKey("_tenant");
|
||||
result.ContainsKey("tenantContext").Should().BeTrue();
|
||||
result.ContainsKey("_tenant").Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -125,7 +125,7 @@ public sealed class TenantNotificationEnricherTests
|
||||
|
||||
// Assert
|
||||
var tenant = result["_tenant"]!.AsObject();
|
||||
tenant.Should().NotContainKey("actor");
|
||||
tenant.ContainsKey("actor").Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -144,7 +144,7 @@ public sealed class TenantNotificationEnricherTests
|
||||
|
||||
// Assert
|
||||
var tenant = result["_tenant"]!.AsObject();
|
||||
tenant.Should().NotContainKey("correlationId");
|
||||
tenant.ContainsKey("correlationId").Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -163,7 +163,7 @@ public sealed class TenantNotificationEnricherTests
|
||||
|
||||
// Assert
|
||||
var tenant = result["_tenant"]!.AsObject();
|
||||
tenant.Should().NotContainKey("timestamp");
|
||||
tenant.ContainsKey("timestamp").Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -206,7 +206,7 @@ public sealed class TenantNotificationEnricherTests
|
||||
|
||||
// Assert
|
||||
var tenant = result["_tenant"]!.AsObject();
|
||||
tenant.Should().ContainKey("claims");
|
||||
tenant.ContainsKey("claims").Should().BeTrue();
|
||||
var claims = tenant["claims"]!.AsObject();
|
||||
claims["role"]!.GetValue<string>().Should().Be("admin");
|
||||
claims["department"]!.GetValue<string>().Should().Be("engineering");
|
||||
@@ -462,9 +462,9 @@ public sealed class TenantNotificationEnricherExtensionsTests
|
||||
var result = enricher.EnrichFromDictionary(data);
|
||||
|
||||
// Assert
|
||||
result.Should().ContainKey("eventType");
|
||||
result.Should().ContainKey("value");
|
||||
result.Should().ContainKey("_tenant");
|
||||
result.ContainsKey("eventType").Should().BeTrue();
|
||||
result.ContainsKey("value").Should().BeTrue();
|
||||
result.ContainsKey("_tenant").Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -3049,9 +3049,6 @@ paths:
|
||||
/api/v2/notify/retention/cleanup: {}
|
||||
/api/v2/notify/retention/cleanup/preview: {}
|
||||
/api/v2/notify/retention/cleanup/last: {}
|
||||
/api/v2/notify/rules: {}
|
||||
/api/v2/notify/templates: {}
|
||||
/api/v2/notify/incidents: {}
|
||||
/api/v2/rules: {}
|
||||
/api/v2/templates: {}
|
||||
/api/v2/incidents: {}
|
||||
@@ -3076,4 +3073,5 @@ app.TryRefreshStellaRouterEndpoints(routerOptions);
|
||||
|
||||
app.Run();
|
||||
|
||||
// Make Program class accessible to test projects using WebApplicationFactory
|
||||
public partial class Program;
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../../Notify/__Libraries/StellaOps.Notify.Storage.Postgres/StellaOps.Notify.Storage.Postgres.csproj" />
|
||||
<ProjectReference Include="../../../Notify/__Libraries/StellaOps.Notify.Persistence/StellaOps.Notify.Persistence.csproj" />
|
||||
<ProjectReference Include="../../../Notify/__Libraries/StellaOps.Notify.Queue/StellaOps.Notify.Queue.csproj" />
|
||||
<ProjectReference Include="../../../Notify/__Libraries/StellaOps.Notify.Engine/StellaOps.Notify.Engine.csproj" />
|
||||
<ProjectReference Include="../StellaOps.Notifier.Worker/StellaOps.Notifier.Worker.csproj" />
|
||||
<ProjectReference Include="../../../__Libraries/StellaOps.Router.AspNet/StellaOps.Router.AspNet.csproj" />
|
||||
<ProjectReference Include="../../../Router/__Libraries/StellaOps.Router.AspNet/StellaOps.Router.AspNet.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -6,7 +6,8 @@ using StellaOps.AirGap.Policy;
|
||||
using StellaOps.Notifier.Worker.Channels;
|
||||
using StellaOps.Notify.Engine;
|
||||
using StellaOps.Notify.Queue;
|
||||
using StellaOps.Notify.Storage.Postgres;
|
||||
using StellaOps.Notify.Persistence.Extensions;
|
||||
using StellaOps.Notify.Persistence.Postgres;
|
||||
using StellaOps.Notifier.Worker.Storage;
|
||||
using StellaOps.Notifier.Worker.Dispatch;
|
||||
using StellaOps.Notifier.Worker.Options;
|
||||
@@ -30,7 +31,7 @@ builder.Services.Configure<NotifierWorkerOptions>(builder.Configuration.GetSecti
|
||||
builder.Services.AddSingleton(TimeProvider.System);
|
||||
|
||||
var postgresSection = builder.Configuration.GetSection("notifier:storage:postgres");
|
||||
builder.Services.AddNotifyPostgresStorage(builder.Configuration, postgresSection.Path);
|
||||
builder.Services.AddNotifyPersistence(builder.Configuration, postgresSection.Path);
|
||||
|
||||
builder.Services.AddAirGapEgressPolicy(builder.Configuration);
|
||||
|
||||
|
||||
@@ -10,18 +10,18 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Cronos" Version="0.9.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="10.0.0" />
|
||||
<PackageReference Include="Cronos" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../../Notify/__Libraries/StellaOps.Notify.Models/StellaOps.Notify.Models.csproj" />
|
||||
<ProjectReference Include="../../../Notify/__Libraries/StellaOps.Notify.Queue/StellaOps.Notify.Queue.csproj" />
|
||||
<ProjectReference Include="../../../Notify/__Libraries/StellaOps.Notify.Storage.Postgres/StellaOps.Notify.Storage.Postgres.csproj" />
|
||||
<ProjectReference Include="../../../Notify/__Libraries/StellaOps.Notify.Persistence/StellaOps.Notify.Persistence.csproj" />
|
||||
<ProjectReference Include="../../../Notify/__Libraries/StellaOps.Notify.Engine/StellaOps.Notify.Engine.csproj" />
|
||||
<ProjectReference Include="../../../AirGap/StellaOps.AirGap.Policy/StellaOps.AirGap.Policy/StellaOps.AirGap.Policy.csproj" />
|
||||
<ProjectReference Include="../../../__Libraries/StellaOps.Cryptography/StellaOps.Cryptography.csproj" />
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Notifier.WebService", "StellaOps.Notifier.WebService\StellaOps.Notifier.WebService.csproj", "{D14281B8-BC8E-4D31-B1FC-E3C9565F7482}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Notifier.Worker", "StellaOps.Notifier.Worker\StellaOps.Notifier.Worker.csproj", "{A134A9AE-CC9E-4AC7-8CD7-8C7BBF45CD02}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Notifier.Tests", "StellaOps.Notifier.Tests\StellaOps.Notifier.Tests.csproj", "{1DFEC971-61F4-4E63-A903-C04062C84967}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{D14281B8-BC8E-4D31-B1FC-E3C9565F7482}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D14281B8-BC8E-4D31-B1FC-E3C9565F7482}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D14281B8-BC8E-4D31-B1FC-E3C9565F7482}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{D14281B8-BC8E-4D31-B1FC-E3C9565F7482}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{D14281B8-BC8E-4D31-B1FC-E3C9565F7482}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{D14281B8-BC8E-4D31-B1FC-E3C9565F7482}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{D14281B8-BC8E-4D31-B1FC-E3C9565F7482}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D14281B8-BC8E-4D31-B1FC-E3C9565F7482}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D14281B8-BC8E-4D31-B1FC-E3C9565F7482}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{D14281B8-BC8E-4D31-B1FC-E3C9565F7482}.Release|x64.Build.0 = Release|Any CPU
|
||||
{D14281B8-BC8E-4D31-B1FC-E3C9565F7482}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{D14281B8-BC8E-4D31-B1FC-E3C9565F7482}.Release|x86.Build.0 = Release|Any CPU
|
||||
{A134A9AE-CC9E-4AC7-8CD7-8C7BBF45CD02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A134A9AE-CC9E-4AC7-8CD7-8C7BBF45CD02}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A134A9AE-CC9E-4AC7-8CD7-8C7BBF45CD02}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{A134A9AE-CC9E-4AC7-8CD7-8C7BBF45CD02}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{A134A9AE-CC9E-4AC7-8CD7-8C7BBF45CD02}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{A134A9AE-CC9E-4AC7-8CD7-8C7BBF45CD02}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{A134A9AE-CC9E-4AC7-8CD7-8C7BBF45CD02}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A134A9AE-CC9E-4AC7-8CD7-8C7BBF45CD02}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A134A9AE-CC9E-4AC7-8CD7-8C7BBF45CD02}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{A134A9AE-CC9E-4AC7-8CD7-8C7BBF45CD02}.Release|x64.Build.0 = Release|Any CPU
|
||||
{A134A9AE-CC9E-4AC7-8CD7-8C7BBF45CD02}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A134A9AE-CC9E-4AC7-8CD7-8C7BBF45CD02}.Release|x86.Build.0 = Release|Any CPU
|
||||
{1DFEC971-61F4-4E63-A903-C04062C84967}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1DFEC971-61F4-4E63-A903-C04062C84967}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1DFEC971-61F4-4E63-A903-C04062C84967}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{1DFEC971-61F4-4E63-A903-C04062C84967}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{1DFEC971-61F4-4E63-A903-C04062C84967}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{1DFEC971-61F4-4E63-A903-C04062C84967}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{1DFEC971-61F4-4E63-A903-C04062C84967}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1DFEC971-61F4-4E63-A903-C04062C84967}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1DFEC971-61F4-4E63-A903-C04062C84967}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{1DFEC971-61F4-4E63-A903-C04062C84967}.Release|x64.Build.0 = Release|Any CPU
|
||||
{1DFEC971-61F4-4E63-A903-C04062C84967}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{1DFEC971-61F4-4E63-A903-C04062C84967}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Reference in New Issue
Block a user