diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DriverHostActorTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DriverHostActorTests.cs index 7dfc2fc3..2429e610 100644 --- a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DriverHostActorTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Drivers/DriverHostActorTests.cs @@ -157,6 +157,48 @@ public sealed class DriverHostActorTests : RuntimeActorTestBase plan.PredicateSource.ShouldContain("ctx.GetTag"); } + /// Bootstrap-restore: a node that already has an Applied NodeDeploymentState + /// row for a ScriptedAlarm-carrying deployment re-forwards the + /// on PreStart (no dispatch needed), so a + /// restarted node restores its live ScriptedAlarm children. + [Fact] + public void Restore_on_bootstrap_forwards_EquipmentScriptedAlarms_to_scripted_alarm_host() + { + var db = NewInMemoryDbFactory(); + var deploymentId = SeedDeploymentWithScriptedAlarm(db, RevA); + + // Seed an Applied NodeDeploymentState row so Bootstrap() detects the Applied branch and + // calls RestoreApplied — no DispatchDeployment needed. + using (var ctx = db.CreateDbContext()) + { + ctx.NodeDeploymentStates.Add(new Configuration.Entities.NodeDeploymentState + { + NodeId = TestNode.Value, + DeploymentId = deploymentId.Value, + Status = NodeDeploymentStatus.Applied, + StartedAtUtc = DateTime.UtcNow, + AppliedAtUtc = DateTime.UtcNow, + }); + ctx.SaveChanges(); + } + + var coordinator = CreateTestProbe(); + var alarmHost = CreateTestProbe(); + // No DispatchDeployment — Bootstrap() should detect the Applied row and run RestoreApplied, + // which routes through PushDesiredSubscriptions and forwards ApplyScriptedAlarms. + Sys.ActorOf(DriverHostActor.Props( + db, TestNode, coordinator.Ref, + localRoles: new HashSet { "driver" }, + scriptedAlarmHostOverride: alarmHost.Ref)); + + var apply = alarmHost.ExpectMsg(TimeSpan.FromSeconds(5)); + var plan = apply.Plans.ShouldHaveSingleItem(); + plan.ScriptedAlarmId.ShouldBe("al-1"); + plan.EquipmentId.ShouldBe("eq-1"); + plan.Name.ShouldBe("Overheat"); + plan.PredicateSource.ShouldContain("ctx.GetTag"); + } + private static DeploymentId SeedDeploymentWithScriptedAlarm( IDbContextFactory db, RevisionHash rev) {