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:
@@ -9,7 +9,7 @@ using ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Adapters;
|
||||
namespace ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// DataConnectionLayer-003: structural regression guard. RealOpcUaClient's
|
||||
/// Structural regression guard. RealOpcUaClient's
|
||||
/// monitored-item / callback maps are read from the OPC UA SDK's publish threads
|
||||
/// concurrently with subscribe/disconnect mutations on other threads. They must be
|
||||
/// concurrent collections, not plain Dictionary. This is verified structurally
|
||||
@@ -18,6 +18,10 @@ namespace ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests;
|
||||
/// </summary>
|
||||
public class RealOpcUaClientThreadSafetyTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Verifies that the shared dictionary fields of the OPC UA client are concurrent collections.
|
||||
/// </summary>
|
||||
/// <param name="fieldName">The name of the field that is inspected.</param>
|
||||
[Theory]
|
||||
[InlineData("_callbacks")]
|
||||
[InlineData("_monitoredItems")]
|
||||
@@ -40,7 +44,7 @@ public class RealOpcUaClientThreadSafetyTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DataConnectionLayer-019: <see cref="OpcUaDataConnection"/> previously kept a
|
||||
/// <see cref="OpcUaDataConnection"/> previously kept a
|
||||
/// dead <c>Dictionary<string,string> _subscriptionHandles</c> field that was
|
||||
/// written and removed across thread-pool continuations but never read. Plain
|
||||
/// Dictionary writes from concurrent post-await continuations are racy; the
|
||||
@@ -53,6 +57,7 @@ public class RealOpcUaClientThreadSafetyTests
|
||||
/// </summary>
|
||||
public class OpcUaDataConnectionThreadSafetyTests
|
||||
{
|
||||
/// <summary>Verifies that the OPC UA data connection has no non-concurrent shared dictionary field.</summary>
|
||||
[Fact]
|
||||
public void DCL019_OpcUaDataConnection_HasNoNonConcurrentSharedDictionary()
|
||||
{
|
||||
@@ -76,14 +81,15 @@ public class OpcUaDataConnectionThreadSafetyTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DataConnectionLayer-012: secure-by-default certificate handling.
|
||||
/// Secure-by-default certificate handling.
|
||||
/// </summary>
|
||||
public class OpcUaCertificateDefaultTests
|
||||
{
|
||||
/// <summary>Verifies that automatic acceptance of untrusted certificates defaults to false.</summary>
|
||||
[Fact]
|
||||
public void DCL012_OpcUaConnectionOptions_AutoAcceptUntrustedCerts_DefaultsToFalse()
|
||||
{
|
||||
// Regression test for DataConnectionLayer-012. AutoAcceptUntrustedCerts defaulted
|
||||
// Regression test: AutoAcceptUntrustedCerts defaulted
|
||||
// to true, accepting every server certificate unconditionally and defeating the
|
||||
// Sign / SignAndEncrypt security modes against an active man-in-the-middle. A
|
||||
// secure-by-default posture rejects untrusted certs unless explicitly opted in.
|
||||
@@ -93,7 +99,7 @@ public class OpcUaCertificateDefaultTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DataConnectionLayer-014: the DCL-012 auto-accept-certificate security warning is
|
||||
/// The auto-accept-certificate security warning is
|
||||
/// only effective if RealOpcUaClient is built with a real logger. The only production
|
||||
/// path that constructs one is RealOpcUaClientFactory.Create(); that factory must
|
||||
/// thread a logger through, otherwise the warning sinks into NullLogger and an
|
||||
@@ -109,12 +115,13 @@ public class RealOpcUaClientFactoryLoggerTests
|
||||
return (ILogger<RealOpcUaClient>)field!.GetValue(client)!;
|
||||
}
|
||||
|
||||
/// <summary>Verifies that the real OPC UA client factory creates a client with a real logger.</summary>
|
||||
[Fact]
|
||||
public void DCL014_RealOpcUaClientFactory_CreatesClientWithRealLogger()
|
||||
{
|
||||
// Regression test for DataConnectionLayer-014. RealOpcUaClientFactory.Create()
|
||||
// Regression test: RealOpcUaClientFactory.Create()
|
||||
// constructed `new RealOpcUaClient(_globalOptions)` with no logger, so the
|
||||
// DCL-012 man-in-the-middle warning was always discarded by NullLogger in
|
||||
// auto-accept man-in-the-middle warning was always discarded by NullLogger in
|
||||
// production. After the fix the factory accepts an ILoggerFactory and passes a
|
||||
// real ILogger<RealOpcUaClient> into every client it creates.
|
||||
using var loggerFactory = LoggerFactory.Create(b => { });
|
||||
@@ -126,6 +133,7 @@ public class RealOpcUaClientFactoryLoggerTests
|
||||
Assert.NotSame(NullLogger<RealOpcUaClient>.Instance, logger);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that the data connection factory passes its logger through to the real OPC UA client.</summary>
|
||||
[Fact]
|
||||
public void DCL014_DataConnectionFactory_ThreadsLoggerToRealOpcUaClient()
|
||||
{
|
||||
@@ -150,14 +158,15 @@ public class RealOpcUaClientFactoryLoggerTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DataConnectionLayer-009: failover-stability tunables must be configurable.
|
||||
/// Failover-stability tunables must be configurable.
|
||||
/// </summary>
|
||||
public class DataConnectionOptionsStabilityTests
|
||||
{
|
||||
/// <summary>Verifies that the stable connection threshold is configurable and defaults to sixty seconds.</summary>
|
||||
[Fact]
|
||||
public void DCL009_StableConnectionThreshold_IsConfigurable_WithSixtySecondDefault()
|
||||
{
|
||||
// Regression test for DataConnectionLayer-009. The unstable-disconnect failover
|
||||
// Regression test: the unstable-disconnect failover
|
||||
// path used a hard-coded 60s StableConnectionThreshold constant inside
|
||||
// DataConnectionActor. It must live on DataConnectionOptions like the other
|
||||
// tunables (ReconnectInterval, TagResolutionRetryInterval, WriteTimeout) so it
|
||||
@@ -171,7 +180,7 @@ public class DataConnectionOptionsStabilityTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// WP-7: Tests for OPC UA adapter.
|
||||
/// Tests for the OPC UA adapter.
|
||||
/// </summary>
|
||||
public class OpcUaDataConnectionTests
|
||||
{
|
||||
@@ -179,6 +188,7 @@ public class OpcUaDataConnectionTests
|
||||
private readonly IOpcUaClientFactory _mockFactory;
|
||||
private readonly OpcUaDataConnection _adapter;
|
||||
|
||||
/// <summary>Initializes the mocked OPC UA client and the adapter under test.</summary>
|
||||
public OpcUaDataConnectionTests()
|
||||
{
|
||||
_mockClient = Substitute.For<IOpcUaClient>();
|
||||
@@ -187,6 +197,8 @@ public class OpcUaDataConnectionTests
|
||||
_adapter = new OpcUaDataConnection(_mockFactory, NullLogger<OpcUaDataConnection>.Instance);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that connecting sets the status to connected.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Connect_SetsStatusToConnected()
|
||||
{
|
||||
@@ -201,6 +213,8 @@ public class OpcUaDataConnectionTests
|
||||
await _mockClient.Received(1).ConnectAsync("opc.tcp://localhost:4840", Arg.Any<OpcUaConnectionOptions?>(), Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
/// <summary>Verifies that disconnecting sets the status to disconnected.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Disconnect_SetsStatusToDisconnected()
|
||||
{
|
||||
@@ -211,10 +225,12 @@ public class OpcUaDataConnectionTests
|
||||
Assert.Equal(ConnectionHealth.Disconnected, _adapter.Status);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that concurrent connection-lost notifications raise the disconnected event exactly once.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task DCL013_ConcurrentConnectionLost_RaisesDisconnectedExactlyOnce()
|
||||
{
|
||||
// Regression test for DataConnectionLayer-013. RaiseDisconnected used a
|
||||
// Regression test: RaiseDisconnected used a
|
||||
// non-atomic check-then-set on a volatile bool: two threads racing through it
|
||||
// (e.g. the keep-alive thread and a ReadAsync failure path, both routed via
|
||||
// OnClientConnectionLost) could both observe _disconnectFired == false and both
|
||||
@@ -250,6 +266,8 @@ public class OpcUaDataConnectionTests
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Verifies that subscribing delegates to the client and returns the subscription id.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Subscribe_DelegatesAndReturnsId()
|
||||
{
|
||||
@@ -263,6 +281,8 @@ public class OpcUaDataConnectionTests
|
||||
Assert.Equal("sub-001", subId);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that a successful write returns a good result.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Write_Success_ReturnsGoodResult()
|
||||
{
|
||||
@@ -277,6 +297,8 @@ public class OpcUaDataConnectionTests
|
||||
Assert.Null(result.ErrorMessage);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that a failed write returns an error result.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Write_Failure_ReturnsError()
|
||||
{
|
||||
@@ -291,6 +313,8 @@ public class OpcUaDataConnectionTests
|
||||
Assert.Contains("0x80000000", result.ErrorMessage);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that reading a value with a bad status returns a bad result.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Read_BadStatus_ReturnsBadResult()
|
||||
{
|
||||
@@ -304,6 +328,8 @@ public class OpcUaDataConnectionTests
|
||||
Assert.False(result.Success);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that reading a value with a good status returns the value.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Read_GoodStatus_ReturnsValue()
|
||||
{
|
||||
@@ -320,10 +346,12 @@ public class OpcUaDataConnectionTests
|
||||
Assert.Equal(QualityCode.Good, result.Value.Quality);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that a batch read returns a value for every requested tag.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task ReadBatch_ReadsAllTags()
|
||||
{
|
||||
// WP2.1b: ReadBatchAsync is TRUE bulk — ONE client ReadValuesAsync call carrying
|
||||
// ReadBatchAsync is TRUE bulk — ONE client ReadValuesAsync call carrying
|
||||
// every requested node, not a per-tag loop.
|
||||
_mockClient.IsConnected.Returns(true);
|
||||
_mockClient.ReadValuesAsync(Arg.Any<IReadOnlyList<string>>(), Arg.Any<CancellationToken>())
|
||||
@@ -340,10 +368,12 @@ public class OpcUaDataConnectionTests
|
||||
Assert.Single(_mockClient.ReceivedCalls(), c => c.GetMethodInfo().Name == "ReadValuesAsync");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that a batch read returns per-tag results when one tag fails.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task DCL007_ReadBatch_ReturnsPerTagResults_WhenOneTagFails()
|
||||
{
|
||||
// Regression test for DataConnectionLayer-007. ReadBatchAsync originally looped
|
||||
// Regression test: ReadBatchAsync originally looped
|
||||
// calling ReadAsync per tag; ReadAsync re-throws any non-cancellation exception, so
|
||||
// a single failing tag aborted the whole batch and the caller got NO results for
|
||||
// the tags that did read successfully — even though ReadResult already carries a
|
||||
@@ -372,13 +402,15 @@ public class OpcUaDataConnectionTests
|
||||
Assert.NotNull(results["bad"].ErrorMessage);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that a batch write returns per-tag results when some tags fail.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task DCL017_WriteBatch_ReturnsPerTagResults_WhenSomeTagsFail()
|
||||
{
|
||||
// Regression test for DataConnectionLayer-017. WriteBatchAsync originally looped
|
||||
// Regression test: WriteBatchAsync originally looped
|
||||
// calling WriteAsync per tag; a mid-batch fault made the whole call throw and the
|
||||
// caller lost the per-tag outcomes for the tags that already wrote. The batch is
|
||||
// now ONE bulk service call (WP2.1b), and the invariant is unchanged: per-node
|
||||
// now ONE bulk service call, and the invariant is unchanged: per-node
|
||||
// failures are reported as failed WriteResult rows and every requested tag is
|
||||
// present in the returned map.
|
||||
_mockClient.IsConnected.Returns(true);
|
||||
@@ -411,6 +443,8 @@ public class OpcUaDataConnectionTests
|
||||
Assert.Single(_mockClient.ReceivedCalls(), c => c.GetMethodInfo().Name == "WriteValuesAsync");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that cancellation aborts the whole batch write.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task DCL017_WriteBatch_CancellationAbortsWholeBatch()
|
||||
{
|
||||
@@ -429,6 +463,8 @@ public class OpcUaDataConnectionTests
|
||||
_adapter.WriteBatchAsync(new Dictionary<string, object?> { ["tag1"] = 1 }, cts.Token));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that operations throw when the adapter is not connected.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task NotConnected_ThrowsOnOperations()
|
||||
{
|
||||
@@ -438,6 +474,8 @@ public class OpcUaDataConnectionTests
|
||||
_adapter.ReadAsync("tag1"));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that disposing the adapter cleans up its resources.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task DisposeAsync_CleansUp()
|
||||
{
|
||||
@@ -450,6 +488,8 @@ public class OpcUaDataConnectionTests
|
||||
|
||||
// --- Configuration Parsing ---
|
||||
|
||||
/// <summary>Verifies that connecting parses every supported configuration key.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Connect_ParsesAllConfigurationKeys()
|
||||
{
|
||||
@@ -487,6 +527,8 @@ public class OpcUaDataConnectionTests
|
||||
Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
/// <summary>Verifies that connecting uses default values when the configuration keys are not provided.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Connect_UsesDefaults_WhenKeysNotProvided()
|
||||
{
|
||||
@@ -511,6 +553,8 @@ public class OpcUaDataConnectionTests
|
||||
Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
/// <summary>Verifies that connecting ignores invalid numeric configuration values.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Connect_IgnoresInvalidNumericValues()
|
||||
{
|
||||
@@ -535,6 +579,8 @@ public class OpcUaDataConnectionTests
|
||||
Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
/// <summary>Verifies that connecting parses the security mode configuration value.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Connect_ParsesSecurityMode()
|
||||
{
|
||||
@@ -551,6 +597,8 @@ public class OpcUaDataConnectionTests
|
||||
Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
/// <summary>Verifies that connecting parses the automatic certificate acceptance setting.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Connect_ParsesAutoAcceptCerts()
|
||||
{
|
||||
@@ -573,6 +621,8 @@ public class OpcUaDataConnectionTests
|
||||
// one, leaking its session/keep-alive/socket per flap AND leaving its stale
|
||||
// ConnectionLost handler wired — so a late keep-alive death on the OLD client
|
||||
// flapped the NEW healthy session (after _disconnectFired was reset).
|
||||
/// <summary>Verifies that reconnecting disposes the previous client and detaches its handlers.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Reconnect_DisposesAndDetachesPreviousClient()
|
||||
{
|
||||
@@ -593,6 +643,8 @@ public class OpcUaDataConnectionTests
|
||||
await clients[1].DidNotReceive().DisposeAsync();
|
||||
}
|
||||
|
||||
/// <summary>Verifies that a connection-lost event from a stale client does not raise a disconnect after a reconnect.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task StaleClientConnectionLost_DoesNotRaiseDisconnected_AfterReconnect()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user