88 lines
3.8 KiB
C#
88 lines
3.8 KiB
C#
using Akka.Actor;
|
|
using Akka.TestKit.Xunit2;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using NSubstitute;
|
|
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Security;
|
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
|
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
|
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;
|
|
using ZB.MOM.WW.ScadaBridge.Security;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.ManagementService.Tests;
|
|
|
|
/// <summary>
|
|
/// Lane K review M1: the process-wide <see cref="RoleMappingCache"/> served a deleted or
|
|
/// changed LDAP-group mapping for up to its TTL on the node that made the change. Every
|
|
/// role-mapping / scope-rule mutation now invalidates it once the change is committed.
|
|
/// </summary>
|
|
public class RoleMappingCacheInvalidationTests : TestKit
|
|
{
|
|
private readonly ISecurityRepository _repo = Substitute.For<ISecurityRepository>();
|
|
private readonly RoleMappingCache _cache = new(TimeProvider.System);
|
|
private readonly ServiceCollection _services = new ServiceCollection().AddTestConfigurationTransaction();
|
|
private List<LdapGroupMapping> _mappings = [new("Ops", "Deployer") { Id = 5 }];
|
|
|
|
/// <summary>Initializes the harness with one Deployer mapping for group "Ops".</summary>
|
|
public RoleMappingCacheInvalidationTests()
|
|
{
|
|
_repo.GetAllMappingsAsync(Arg.Any<CancellationToken>()).Returns(_ => _mappings);
|
|
_repo.GetScopeRulesForMappingAsync(Arg.Any<int>(), Arg.Any<CancellationToken>())
|
|
.Returns(new List<SiteScopeRule>());
|
|
_repo.GetMappingByIdAsync(5, Arg.Any<CancellationToken>()).Returns(_ => _mappings.FirstOrDefault());
|
|
_services.AddScoped(_ => _repo);
|
|
_services.AddScoped(_ => Substitute.For<IAuditService>());
|
|
_services.AddSingleton(_cache);
|
|
}
|
|
|
|
private IActorRef CreateActor() =>
|
|
Sys.ActorOf(Props.Create(() => new ManagementActor(
|
|
_services.BuildServiceProvider(), NullLogger<ManagementActor>.Instance)));
|
|
|
|
private static ManagementEnvelope Admin(object command) =>
|
|
new(new AuthenticatedUser("admin", "Admin", new[] { "Administrator" }, Array.Empty<string>()),
|
|
command, Guid.NewGuid().ToString("N"));
|
|
|
|
private Task<RoleMappingResult> MapOps() => new RoleMapper(_repo, _cache).MapGroupsToRolesAsync(["Ops"]);
|
|
|
|
/// <summary>A deleted mapping is visible to the very next mapping on the same cache.</summary>
|
|
/// <returns>A task that represents the asynchronous operation.</returns>
|
|
[Fact]
|
|
public async Task DeleteRoleMapping_IsVisibleToTheNextMapping()
|
|
{
|
|
Assert.Contains("Deployer", (await MapOps()).Roles); // primes the snapshot
|
|
|
|
_mappings = [];
|
|
CreateActor().Tell(Admin(new DeleteRoleMappingCommand(5)));
|
|
ExpectMsg<ManagementSuccess>(TimeSpan.FromSeconds(5));
|
|
|
|
Assert.Empty((await MapOps()).Roles);
|
|
}
|
|
|
|
/// <summary>Every mapping / scope-rule mutation invalidates the snapshot.</summary>
|
|
/// <returns>A task that represents the asynchronous operation.</returns>
|
|
[Fact]
|
|
public async Task EveryMappingMutation_InvalidatesTheSnapshot()
|
|
{
|
|
object[] commands =
|
|
[
|
|
new CreateRoleMappingCommand("Eng", "Designer"),
|
|
new UpdateRoleMappingCommand(5, "Ops", "Viewer"),
|
|
new AddScopeRuleCommand(5, 2),
|
|
new DeleteScopeRuleCommand(9),
|
|
];
|
|
var actor = CreateActor();
|
|
foreach (var command in commands)
|
|
{
|
|
await MapOps(); // prime
|
|
_repo.ClearReceivedCalls();
|
|
|
|
actor.Tell(Admin(command));
|
|
ExpectMsg<ManagementSuccess>(TimeSpan.FromSeconds(5));
|
|
|
|
await MapOps();
|
|
await _repo.Received(1).GetAllMappingsAsync(Arg.Any<CancellationToken>()); // re-read, not served stale
|
|
}
|
|
}
|
|
}
|