test(alarms): guard native-alarm-during-reconnect is dropped not dead-lettered
This commit is contained in:
+57
@@ -91,6 +91,63 @@ public sealed class DriverInstanceActorNativeAlarmTests : RuntimeActorTestBase
|
||||
parent.ExpectNoMsg(TimeSpan.FromMilliseconds(300));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A native alarm transition that races in while the actor is in <c>Reconnecting</c> is silently
|
||||
/// dropped (debug log only) — it NEVER reaches the parent as
|
||||
/// <see cref="DriverInstanceActor.AttributeAlarmPublished"/> and does NOT dead-letter. The feed
|
||||
/// re-delivers active alarms once the actor re-enters <c>Connected</c>, so dropping here is safe.
|
||||
/// (<see cref="DriverInstanceActor"/> line ~345: the <c>Reconnecting</c> state's
|
||||
/// <c>Receive<NativeAlarmRaised></c> logs a debug message and discards.)
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Native_alarm_during_reconnect_is_dropped_not_forwarded()
|
||||
{
|
||||
var driver = new AlarmSourceStubDriver();
|
||||
var parent = CreateTestProbe();
|
||||
var actor = parent.ChildActorOf(DriverInstanceActor.Props(
|
||||
driver, reconnectInterval: TimeSpan.FromMilliseconds(50)));
|
||||
|
||||
// Drive the actor to Connected first, then push it into Reconnecting via DisconnectObserved.
|
||||
actor.Tell(new DriverInstanceActor.InitializeRequested("{}"));
|
||||
AwaitCondition(() => driver.AlarmSubscriberCount == 1, TimeSpan.FromSeconds(2));
|
||||
|
||||
// One successful alarm-forward from Connected, to confirm the happy path is hot before the test.
|
||||
driver.RaiseAlarm(new AlarmEventArgs(
|
||||
new StubAlarmHandle(),
|
||||
SourceNodeId: "src-node-reconnect",
|
||||
ConditionId: "cond-reconnect",
|
||||
AlarmType: "T",
|
||||
Message: "pre-reconnect raise",
|
||||
Severity: AlarmSeverity.High,
|
||||
SourceTimestampUtc: DateTime.UtcNow,
|
||||
Kind: AlarmTransitionKind.Raise));
|
||||
parent.ExpectMsg<DriverInstanceActor.AttributeAlarmPublished>(TimeSpan.FromSeconds(2));
|
||||
|
||||
// Force Connected → Reconnecting; the alarm handler is detached during this transition.
|
||||
actor.Tell(new DriverInstanceActor.DisconnectObserved("test-induced disconnect"));
|
||||
// Wait until the actor detaches the alarm handler (AlarmSubscriberCount drops to 0).
|
||||
AwaitCondition(() => driver.AlarmSubscriberCount == 0, TimeSpan.FromSeconds(2));
|
||||
|
||||
// Now tell the actor a NativeAlarmRaised (the driver thread can fire this at any time).
|
||||
// In Reconnecting the actor handles NativeAlarmRaised with a debug log and drops it.
|
||||
driver.RaiseAlarm(new AlarmEventArgs(
|
||||
new StubAlarmHandle(),
|
||||
SourceNodeId: "src-node-reconnect",
|
||||
ConditionId: "cond-reconnect",
|
||||
AlarmType: "T",
|
||||
Message: "during-reconnect raise",
|
||||
Severity: AlarmSeverity.High,
|
||||
SourceTimestampUtc: DateTime.UtcNow,
|
||||
Kind: AlarmTransitionKind.Raise));
|
||||
|
||||
// The parent must NOT receive an AttributeAlarmPublished while the actor is Reconnecting.
|
||||
parent.ExpectNoMsg(TimeSpan.FromMilliseconds(300));
|
||||
|
||||
// The actor must still be alive (not crashed/dead-lettered) — a Watch + no Terminated proves it.
|
||||
Watch(actor);
|
||||
parent.ExpectNoMsg(TimeSpan.FromMilliseconds(100)); // still no Terminated
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// After a full reconnect cycle (Connected → Reconnecting → Connected), a single raised alarm still
|
||||
/// yields EXACTLY ONE <see cref="DriverInstanceActor.AttributeAlarmPublished"/> — the
|
||||
|
||||
Reference in New Issue
Block a user