docs(tests): fix CommentChecker findings across tests/ — 13,392 → 0 (repo-wide scan clean)

Comment/XML-doc changes only:
- add summaries to ~10k test methods, fixtures, fakes and helpers
  (+ <param> on theories, <returns> on async Task methods,
  <inheritdoc/> on interface implementations the checker can resolve)
- strip ~2.6k project-tracking references (WP*, P*-*, row-NN, Task N,
  #NN, Component-0NN) from comments, keeping the explanatory text;
  reword false positives in comments only
- real docs on fakes implementing BCL/library interfaces
  (IDisposable, ILogger, IOptionsMonitor, IAsyncLifetime)
- reword the last 5 src/ false positives (CWE-1236, failures-1,
  year-0001, M365)

Only non-comment edits: four one-line nested classes split across lines
so members can carry docs. Build 0 errors / 0 warnings.
This commit is contained in:
Joseph Doherty
2026-10-07 15:05:49 -04:00
parent 0ffd4bdbea
commit 513fa1aa16
998 changed files with 17896 additions and 2395 deletions
@@ -10,7 +10,7 @@ using ZB.MOM.WW.ScadaBridge.HealthMonitoring;
namespace ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests;
/// <summary>Task-10: native alarm subscribe + source-ref routing + unavailable signal.</summary>
/// <summary>Native alarm subscribe + source-ref routing + unavailable signal.</summary>
public class DataConnectionActorAlarmTests : TestKit
{
private readonly ISiteHealthCollector _health = Substitute.For<ISiteHealthCollector>();
@@ -44,6 +44,7 @@ public class DataConnectionActorAlarmTests : TestKit
return (adapter, () => cb);
}
/// <summary>Verifies that an alarm subscription routes a transition to the instance subscriber.</summary>
[Fact]
public void SubscribeAlarms_RoutesTransitionToInstanceSubscriber()
{
@@ -67,10 +68,11 @@ public class DataConnectionActorAlarmTests : TestKit
ExpectMsg<NativeAlarmTransitionUpdate>(u => u.Transition.SourceObjectReference == "Tank01");
}
/// <summary>Verifies that an alarm bound by node id routes its transition to the subscriber.</summary>
[Fact]
public void SubscribeAlarms_NodeIdBinding_RoutesTransition()
{
// Gitea #17 end-to-end: an instance binds a native alarm source by NodeId (the form
// End-to-end: an instance binds a native alarm source by NodeId (the form
// the picker / CSV / config store). The adapter builds the transition's identity via
// OpcUaAlarmMapper.BuildIdentity(binding, SourceName, ConditionName). With the old
// "SourceObjectReference = SourceName" logic the event's name ("pymodbus/plc/HR200")
@@ -105,6 +107,7 @@ public class DataConnectionActorAlarmTests : TestKit
Assert.Equal("pymodbus/plc/HR200.HR200", update.Transition.SourceReference);
}
/// <summary>Verifies that subscribing on an adapter that cannot raise alarms replies with a failure.</summary>
[Fact]
public void SubscribeAlarms_OnNonAlarmCapableAdapter_RepliesFailure()
{
@@ -119,6 +122,7 @@ public class DataConnectionActorAlarmTests : TestKit
ExpectMsg<SubscribeAlarmsResponse>(m => !m.Success && m.ErrorMessage != null);
}
/// <summary>Verifies that a second subscriber with a different filter logs an overwrite warning.</summary>
[Fact]
public void SecondAlarmSubscriber_WithDifferentFilter_LogsOverwriteWarning()
{
@@ -142,8 +146,9 @@ public class DataConnectionActorAlarmTests : TestKit
});
}
// ── M2.4 (#8): conditionFilter is now applied client-side in the actor ──
// ── conditionFilter is now applied client-side in the actor ──
/// <summary>Verifies that a type filter delivers only matching alarm types.</summary>
[Fact]
public void SubscribeAlarms_WithTypeFilter_DeliversOnlyMatchingTypes()
{
@@ -166,6 +171,7 @@ public class DataConnectionActorAlarmTests : TestKit
ExpectMsg<NativeAlarmTransitionUpdate>(u => u.Transition.AlarmTypeName == "AnalogLimit.Hi");
}
/// <summary>Verifies that a null filter delivers all alarm types.</summary>
[Fact]
public void SubscribeAlarms_WithNullFilter_DeliversAllTypes()
{
@@ -184,6 +190,7 @@ public class DataConnectionActorAlarmTests : TestKit
ExpectMsg<NativeAlarmTransitionUpdate>(u => u.Transition.AlarmTypeName == "DiscreteAlarm");
}
/// <summary>Verifies that filter matching ignores letter case and surrounding whitespace.</summary>
[Fact]
public void SubscribeAlarms_FilterMatch_IgnoresCaseAndWhitespace()
{
@@ -205,6 +212,7 @@ public class DataConnectionActorAlarmTests : TestKit
ExpectNoMsg(TimeSpan.FromMilliseconds(250));
}
/// <summary>Verifies that a gateway-wide alarm feed is filtered client-side.</summary>
[Fact]
public void SubscribeAlarms_GatewayWideFeed_IsFilteredClientSide()
{
@@ -234,6 +242,7 @@ public class DataConnectionActorAlarmTests : TestKit
u.Transition.SourceObjectReference == "Reactor" && u.Transition.AlarmTypeName == "HighTemp");
}
/// <summary>Verifies that a filtered subscription still forwards the snapshot-complete sentinel.</summary>
[Fact]
public void SubscribeAlarms_WithFilter_StillForwardsSnapshotCompleteSentinel()
{
@@ -257,6 +266,7 @@ public class DataConnectionActorAlarmTests : TestKit
ExpectMsg<NativeAlarmTransitionUpdate>(u => u.Transition.Kind == AlarmTransitionKind.SnapshotComplete);
}
/// <summary>Verifies that a real snapshot-complete marker with an empty reference is broadcast to a specific source.</summary>
[Fact]
public void SubscribeAlarms_RealEmptyRefSnapshotComplete_IsBroadcastToSpecificSource()
{
@@ -293,13 +303,15 @@ public class DataConnectionActorAlarmTests : TestKit
ExpectMsg<NativeAlarmTransitionUpdate>(u => u.Transition.Kind == AlarmTransitionKind.SnapshotComplete);
}
// ── DataConnectionLayer-023: mid-flight alarm unsubscribe must release the adapter feed ──
// ── Mid-flight alarm unsubscribe must release the adapter feed ──
/// <summary>Verifies that unsubscribing during an in-flight alarm subscribe releases the adapter feed and leaves the actor state clean.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task DCL023_UnsubscribeDuringInFlightAlarmSubscribe_ReleasesAdapterFeed_AndKeepsStateClean()
{
// Regression test for DataConnectionLayer-023. Previously the native-alarm
// subscribe path never inherited the DCL-021 obsolete-completion guard: if the
// Regression test: previously the native-alarm
// subscribe path never inherited the obsolete-completion guard: if the
// last subscriber unsubscribed while the adapter alarm subscribe was in flight,
// HandleUnsubscribeAlarms could not tear down the feed (the subscription id was
// not stored yet), and the late AlarmSubscribeCompleted unconditionally stored
@@ -368,20 +380,22 @@ public class DataConnectionActorAlarmTests : TestKit
"Tank01", Arg.Any<string?>(), Arg.Any<AlarmTransitionCallback>(), Arg.Any<CancellationToken>());
}
// ── DataConnectionLayer-029: a re-subscribe during an orphaned in-flight subscribe
// ── A re-subscribe during an orphaned in-flight subscribe
// must not leak a duplicate adapter feed ──
/// <summary>Verifies that a re-subscribe during an orphaned in-flight subscribe releases the duplicate feed without leaking.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task DCL029_ResubscribeDuringOrphanedInFlightSubscribe_ReleasesDuplicateFeed_NoLeak()
{
// Regression test for DataConnectionLayer-029. The DCL-023 fix clears the in-flight
// Regression test: the mid-flight-unsubscribe fix clears the in-flight
// marker on unsubscribe, which reopens a double-subscribe window: unsubscribe (last
// subscriber, subId not stored yet) → a fresh subscribe for the SAME source sees
// neither a stored id nor an in-flight marker, so it issues a SECOND adapter feed →
// both completions fire. The DCL-023 orphan guard does NOT trigger on either
// both completions fire. The orphan guard does NOT trigger on either
// completion (the re-subscribe re-added the subscriber), so the alarm completion
// handler used to OVERWRITE _alarmSubscriptionIds with the second id — leaking the
// first feed (never unsubscribed, kept streaming). After DCL-029 the handler mirrors
// first feed (never unsubscribed, kept streaming). With the fix the handler mirrors
// the tag-path re-check: when a feed is already stored, the redundant completion
// releases its just-created feed instead of overwriting + leaking.
var sub1Started = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
@@ -413,35 +427,35 @@ public class DataConnectionActorAlarmTests : TestKit
var actor = Sys.ActorOf(Props.Create(() => new DataConnectionActor(
"conn", adapter, _options, _health, _factory, "OpcUa")));
// (1) Subscribe A — adapter subscribe #1 parks, in-flight={Tank01}.
// (1) Subscribe A — the first adapter subscribe parks, in-flight={Tank01}.
actor.Tell(new SubscribeAlarmsRequest("c1", "instA", "conn", "Tank01", null, DateTimeOffset.UtcNow));
await sub1Started.Task.WaitAsync(TimeSpan.FromSeconds(5));
// (2) Last subscriber unsubscribes while subscribe #1 is in flight — clears the
// in-flight marker (DCL-023); subId#1 is not stored yet so no teardown happens.
// (2) Last subscriber unsubscribes while the first subscribe is in flight — clears the
// in-flight marker; the first subscription id is not stored yet so no teardown happens.
actor.Tell(new UnsubscribeAlarmsRequest("unsub-c1", "instA", "conn", "Tank01", DateTimeOffset.UtcNow));
await Task.Delay(150);
// (3) Fresh subscribe for the SAME source before #1 completes — neither a stored id
// (3) Fresh subscribe for the SAME source before the first completes — neither a stored id
// nor an in-flight marker exists, so the actor issues a SECOND adapter subscribe.
actor.Tell(new SubscribeAlarmsRequest("c2", "instB", "conn", "Tank01", null, DateTimeOffset.UtcNow));
await sub2Started.Task.WaitAsync(TimeSpan.FromSeconds(5));
// (4) Complete subscribe #1 → a subscriber exists again (B re-added), so the orphan
// guard does NOT fire and subId#1 is stored as the live feed.
// (4) Complete the first subscribe → a subscriber exists again (B re-added), so the orphan
// guard does NOT fire and its subscription id is stored as the live feed.
sub1Release.SetResult("alarm-sub-1");
await Task.Delay(150);
// (5) Complete subscribe #2 → a feed is already stored, so this redundant completion
// releases its just-created feed (#2) instead of overwriting + leaking subId#1.
// (5) Complete the second subscribe → a feed is already stored, so this redundant completion
// releases its just-created feed instead of overwriting + leaking the first subscription id.
sub2Release.SetResult("alarm-sub-2");
await Task.Delay(300);
// The duplicate feed (#2) is released exactly once; the first feed (#1) is retained.
// The duplicate (second) feed is released exactly once; the first feed is retained.
await alarmable.Received(1).UnsubscribeAlarmsAsync("alarm-sub-2", Arg.Any<CancellationToken>());
await alarmable.DidNotReceive().UnsubscribeAlarmsAsync("alarm-sub-1", Arg.Any<CancellationToken>());
// The retained feed (#1) is what a later unsubscribe tears down — proving subId#1,
// The retained (first) feed is what a later unsubscribe tears down — proving the first subscription id,
// not the duplicate, is the id _alarmSubscriptionIds actually tracks (no leak).
actor.Tell(new UnsubscribeAlarmsRequest("unsub-c2", "instB", "conn", "Tank01", DateTimeOffset.UtcNow));
await Task.Delay(200);