Merge #597/#599: real UnshelveTime, commented re-ack reports, native ack refused off-Primary, /alerts ack-path test; surgically-added raw nodes announced, equipment-with-references removal keeps references severed; Backing* parity guard
Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
using Akka.Hosting;
|
||||
using Akka.TestKit.Xunit2;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.AdminUI.Clients;
|
||||
using ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Acls;
|
||||
using ZB.MOM.WW.OtOpcUa.Commons.Messages.Admin;
|
||||
using ZB.MOM.WW.OtOpcUa.Commons.Messages.Mesh;
|
||||
using ZB.MOM.WW.OtOpcUa.Commons.OpcUa;
|
||||
using ZB.MOM.WW.OtOpcUa.ControlPlane;
|
||||
using ZB.MOM.WW.OtOpcUa.ControlPlane.AdminOperations;
|
||||
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Gitea #597 — the AdminUI <c>/alerts</c> acknowledge / shelve path, from the page's client call down to
|
||||
/// the command the cluster receives: <see cref="AdminOperationsClient"/> (what <c>Alerts.razor</c>'s
|
||||
/// per-row buttons call) Asks the real <see cref="AdminOperationsActor"/> registered under
|
||||
/// <see cref="AdminOperationsActorKey"/>, which maps the request to an <see cref="AlarmCommand"/> and hands
|
||||
/// it to the mesh transport. Until now only the actor half had a test; the client seam the page goes
|
||||
/// through had none.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The razor click handler itself is not driven here — this repo has no bUnit. What it adds on top of the
|
||||
/// client call is the operator name and <c>comment: null</c>, both reproduced below exactly as the page
|
||||
/// passes them.
|
||||
/// </remarks>
|
||||
public sealed class AlertsAckPathTests : TestKit
|
||||
{
|
||||
private (AdminOperationsClient Client, Akka.TestKit.TestProbe Mesh) Wire()
|
||||
{
|
||||
var mesh = CreateTestProbe("mesh-router");
|
||||
var actor = Sys.ActorOf(AdminOperationsActor.Props(
|
||||
AclScopeTestDb.Factory($"alerts-ack-{Guid.NewGuid():N}"),
|
||||
coordinator: CreateTestProbe("coordinator").Ref,
|
||||
probes: Enumerable.Empty<IDriverProbe>(),
|
||||
meshRouter: mesh.Ref));
|
||||
var registry = new ActorRegistry();
|
||||
registry.Register<AdminOperationsActorKey>(actor);
|
||||
return (new AdminOperationsClient(registry), mesh);
|
||||
}
|
||||
|
||||
/// <summary>The page's Acknowledge reaches the cluster as an <c>Acknowledge</c> AlarmCommand on the
|
||||
/// <c>alarm-commands</c> topic carrying the alarm id and the operator, and the page is told it was sent.</summary>
|
||||
[Fact]
|
||||
public async Task Acknowledge_from_the_alerts_page_dispatches_an_Acknowledge_command_and_reports_sent()
|
||||
{
|
||||
var (client, mesh) = Wire();
|
||||
|
||||
var result = await client.AcknowledgeAlarmAsync("alarm-42", "operator-jo", comment: null, CancellationToken.None);
|
||||
|
||||
result.Ok.ShouldBeTrue();
|
||||
result.Message.ShouldBeNull();
|
||||
var sent = mesh.ExpectMsg<MeshCommand>(TimeSpan.FromSeconds(5));
|
||||
sent.Topic.ShouldBe(AlarmCommandsTopic.Name);
|
||||
var command = sent.Message.ShouldBeOfType<AlarmCommand>();
|
||||
command.AlarmId.ShouldBe("alarm-42");
|
||||
command.Operation.ShouldBe("Acknowledge");
|
||||
command.User.ShouldBe("operator-jo");
|
||||
command.Comment.ShouldBeNull();
|
||||
command.UnshelveAtUtc.ShouldBeNull();
|
||||
}
|
||||
|
||||
/// <summary>The page's timed shelve carries its expiry through to the command — the instant the engine
|
||||
/// projects as the node's <c>UnshelveTime</c>.</summary>
|
||||
[Fact]
|
||||
public async Task Timed_shelve_from_the_alerts_page_carries_its_expiry_to_the_command()
|
||||
{
|
||||
var (client, mesh) = Wire();
|
||||
var until = new DateTime(2026, 10, 8, 12, 30, 0, DateTimeKind.Utc);
|
||||
|
||||
var result = await client.ShelveAlarmAsync(
|
||||
"alarm-7", "operator-kim", ShelveKind.Timed, unshelveAtUtc: until, comment: null, CancellationToken.None);
|
||||
|
||||
result.Ok.ShouldBeTrue();
|
||||
var command = mesh.ExpectMsg<MeshCommand>(TimeSpan.FromSeconds(5)).Message.ShouldBeOfType<AlarmCommand>();
|
||||
command.Operation.ShouldBe("TimedShelve");
|
||||
command.UnshelveAtUtc.ShouldBe(until);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user