feat(management): IsMesReportable on alarm commands, IsMesReportableOverride on SetInstanceAlarmOverride

Claude-Session: https://claude.ai/code/session_01Y5ef34iUUMjmwnMpL9xgmB
This commit is contained in:
Joseph Doherty
2026-09-11 10:04:17 -04:00
parent c8a1bcef98
commit 63ec226582
4 changed files with 128 additions and 7 deletions
@@ -1014,6 +1014,112 @@ public class ManagementActorTests : TestKit, IDisposable
Assert.Contains("Valid values:", response.Error);
}
[Fact]
public void AddTemplateAlarm_CarriesIsMesReportable()
{
// The MES-reportable flag rides AddTemplateAlarmCommand as a trailing
// optional (additive-only wire contract) and must reach the TemplateAlarm
// the handler hands to TemplateService — verified at the repository
// boundary, which is where the entity is persisted.
var template = new Template("T1") { Id = 1 };
_templateRepo.GetTemplateByIdAsync(1, Arg.Any<CancellationToken>()).Returns(template);
_templateRepo.GetAllTemplatesForAnalysisAsync(Arg.Any<CancellationToken>())
.Returns(new List<Template> { template });
_templateRepo.GetAllTemplatesAsync(Arg.Any<CancellationToken>())
.Returns(new List<Template> { template });
TemplateAlarm? added = null;
_templateRepo
.When(r => r.AddTemplateAlarmAsync(Arg.Any<TemplateAlarm>(), Arg.Any<CancellationToken>()))
.Do(ci => added = ci.Arg<TemplateAlarm>());
_services.AddScoped<TemplateService>();
var actor = CreateActor();
var envelope = Envelope(
new AddTemplateAlarmCommand(1, "HighTemp", "HiLo", 500, null, null, false, IsMesReportable: true),
"Designer");
actor.Tell(envelope);
ExpectMsg<ManagementSuccess>(TimeSpan.FromSeconds(5));
Assert.NotNull(added);
Assert.True(added!.IsMesReportable);
}
[Fact]
public void UpdateTemplateAlarm_CarriesIsMesReportable()
{
var template = new Template("T1") { Id = 1 };
var existing = new TemplateAlarm("HighTemp")
{
Id = 5,
TemplateId = 1,
TriggerType = AlarmTriggerType.HiLo,
PriorityLevel = 100,
IsMesReportable = false
};
_templateRepo.GetTemplateAlarmByIdAsync(5, Arg.Any<CancellationToken>()).Returns(existing);
_templateRepo.GetTemplateByIdAsync(1, Arg.Any<CancellationToken>()).Returns(template);
_templateRepo.GetAllTemplatesAsync(Arg.Any<CancellationToken>())
.Returns(new List<Template> { template });
TemplateAlarm? updated = null;
_templateRepo
.When(r => r.UpdateTemplateAlarmAsync(Arg.Any<TemplateAlarm>(), Arg.Any<CancellationToken>()))
.Do(ci => updated = ci.Arg<TemplateAlarm>());
_services.AddScoped<TemplateService>();
var actor = CreateActor();
var envelope = Envelope(
new UpdateTemplateAlarmCommand(5, "HighTemp", "HiLo", 500, null, null, false, IsMesReportable: true),
"Designer");
actor.Tell(envelope);
ExpectMsg<ManagementSuccess>(TimeSpan.FromSeconds(5));
Assert.NotNull(updated);
Assert.True(updated!.IsMesReportable);
}
[Fact]
public void SetInstanceAlarmOverride_PassesIsMesReportableOverride()
{
// false is the interesting case: it is distinct from the null "inherit"
// default, so a dropped argument would read as "inherit" rather than
// "explicitly not reportable".
var template = new Template("T1") { Id = 1 };
template.Alarms.Add(new TemplateAlarm("HighTemp")
{
Id = 5,
TemplateId = 1,
TriggerType = AlarmTriggerType.HiLo,
PriorityLevel = 100
});
var instance = new Instance("Inst1") { Id = 10, TemplateId = 1, SiteId = 1 };
_templateRepo.GetInstanceByIdAsync(10, Arg.Any<CancellationToken>()).Returns(instance);
_templateRepo.GetAllTemplatesAsync(Arg.Any<CancellationToken>())
.Returns(new List<Template> { template });
_templateRepo.GetAlarmOverrideAsync(10, "HighTemp", Arg.Any<CancellationToken>())
.Returns((InstanceAlarmOverride?)null);
InstanceAlarmOverride? persisted = null;
_templateRepo
.When(r => r.AddInstanceAlarmOverrideAsync(Arg.Any<InstanceAlarmOverride>(), Arg.Any<CancellationToken>()))
.Do(ci => persisted = ci.Arg<InstanceAlarmOverride>());
var actor = CreateActor();
var envelope = Envelope(
new SetInstanceAlarmOverrideCommand(10, "HighTemp", null, null, IsMesReportableOverride: false),
"Deployer");
actor.Tell(envelope);
ExpectMsg<ManagementSuccess>(TimeSpan.FromSeconds(5));
Assert.NotNull(persisted);
Assert.False(persisted!.IsMesReportableOverride);
}
[Fact]
public void UpdateAttribute_ValidScalar_PersistsValueAndKeepsFixedFields()
{