Files
lmxopcua/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests/OpcUaClientDiagnosticsTests.cs
T

112 lines
3.8 KiB
C#

using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests;
/// <summary>#276 — counters are thread-safe and surface through <c>DriverHealth.Diagnostics</c>.</summary>
[Trait("Category", "Unit")]
public sealed class OpcUaClientDiagnosticsTests
{
[Fact]
public void Fresh_snapshot_is_all_zero_with_the_full_key_set()
{
var snap = new OpcUaClientDiagnostics().Snapshot();
snap.Keys.ShouldBe(
[
"PublishResponseCount", "NotificationCount", "DataChangeCount", "BadStatusValueCount",
"PublishErrorCount", "KeepAliveMissCount", "ReconnectAttemptCount", "ReconnectSuccessCount",
"ReconnectExhaustedCount", "LastReconnectUtcTicks", "ReadCallCount", "ReadFailureCount",
"WriteCallCount", "WriteFailureCount", "ChunkedRequestCount",
], ignoreOrder: true);
snap.Values.ShouldAllBe(v => v == 0);
}
[Fact]
public void Each_recorder_moves_exactly_its_own_counter()
{
var d = new OpcUaClientDiagnostics();
d.RecordPublishResponse();
d.RecordNotifications(3);
d.RecordDataChange(bad: false);
d.RecordDataChange(bad: true);
d.RecordPublishError();
d.RecordKeepAliveMiss();
d.RecordReconnectAttempt();
d.RecordReconnectSucceeded();
d.RecordReconnectExhausted();
d.RecordRead(failed: true);
d.RecordWrite(failed: false);
d.RecordChunkedRequest();
var s = d.Snapshot();
s["PublishResponseCount"].ShouldBe(1);
s["NotificationCount"].ShouldBe(3);
s["DataChangeCount"].ShouldBe(2);
s["BadStatusValueCount"].ShouldBe(1);
s["PublishErrorCount"].ShouldBe(1);
s["KeepAliveMissCount"].ShouldBe(1);
s["ReconnectAttemptCount"].ShouldBe(1);
s["ReconnectSuccessCount"].ShouldBe(1);
s["ReconnectExhaustedCount"].ShouldBe(1);
s["LastReconnectUtcTicks"].ShouldBeGreaterThan(0);
s["ReadCallCount"].ShouldBe(1);
s["ReadFailureCount"].ShouldBe(1);
s["WriteCallCount"].ShouldBe(1);
s["WriteFailureCount"].ShouldBe(0);
s["ChunkedRequestCount"].ShouldBe(1);
}
[Fact]
public void Concurrent_increments_do_not_lose_updates()
{
var d = new OpcUaClientDiagnostics();
const int threads = 8, each = 5_000;
Parallel.For(0, threads, _ =>
{
for (var i = 0; i < each; i++) { d.RecordDataChange(bad: i % 2 == 0); d.RecordNotifications(2); }
});
var s = d.Snapshot();
s["DataChangeCount"].ShouldBe(threads * each);
s["BadStatusValueCount"].ShouldBe(threads * each / 2);
s["NotificationCount"].ShouldBe(threads * each * 2);
}
[Fact]
public void Snapshot_is_a_point_in_time_copy()
{
var d = new OpcUaClientDiagnostics();
var before = d.Snapshot();
d.RecordKeepAliveMiss();
before["KeepAliveMissCount"].ShouldBe(0);
d.Snapshot()["KeepAliveMissCount"].ShouldBe(1);
}
[Fact]
public void GetHealth_carries_the_diagnostics_and_keeps_state_fields()
{
using var drv = new OpcUaClientDriver(new OpcUaClientDriverOptions(), "opcua-diag");
drv.DiagnosticsForTest.RecordKeepAliveMiss();
drv.DiagnosticsForTest.RecordKeepAliveMiss();
var h = drv.GetHealth();
h.State.ShouldBe(DriverState.Unknown);
h.Diagnostics.ShouldNotBeNull();
h.Diagnostics!["KeepAliveMissCount"].ShouldBe(2);
}
[Fact]
public void DriverHealth_without_diagnostics_stays_back_compatible()
{
var h = new DriverHealth(DriverState.Healthy, null, null);
h.Diagnostics.ShouldBeNull();
h.ShouldBe(new DriverHealth(DriverState.Healthy, null, null));
}
}