fix(core-abstractions): resolve Low code-review findings (Core.Abstractions-004,005,006,007,008)
- Core.Abstractions-004: guard DriverTypeRegistry.Register with a Lock so concurrent registrations are atomic. - Core.Abstractions-005: narrow PollGroupEngine catch blocks to non-fatal exceptions, add optional onError callback, tolerate disposed-CTS races. - Core.Abstractions-006: document the deliberate int-vs-uint asymmetry on IHistoryProvider.ReadEventsAsync / IHistorianDataSource.ReadEventsAsync. - Core.Abstractions-007: pin the gaps with PollGroupEngine + DriverHealth contract tests. - Core.Abstractions-008: correct XML docs on DriverHealth.LastError and the optional / required asymmetry on the history-read surfaces. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Covers <see cref="DriverHealth"/> shape invariants — added to lock down the documented
|
||||
/// contract after Core.Abstractions-008 reworded the <c>LastError</c> remark.
|
||||
/// </summary>
|
||||
public sealed class DriverHealthTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Core.Abstractions-008: <c>DriverHealth.LastError</c> is not constrained by the
|
||||
/// <c>State</c> enum — a Healthy driver may legitimately retain the last error from a
|
||||
/// recovered failure (for diagnostics), and Degraded / Reconnecting / Faulted states may
|
||||
/// all carry a non-null message. The old XML doc "null when state is Healthy" was wrong;
|
||||
/// this test makes the type's actual contract explicit so future doc churn cannot drift.
|
||||
/// </summary>
|
||||
[Theory]
|
||||
[InlineData(DriverState.Unknown)]
|
||||
[InlineData(DriverState.Initializing)]
|
||||
[InlineData(DriverState.Healthy)]
|
||||
[InlineData(DriverState.Degraded)]
|
||||
[InlineData(DriverState.Reconnecting)]
|
||||
[InlineData(DriverState.Faulted)]
|
||||
public void LastError_IsIndependent_OfState(DriverState state)
|
||||
{
|
||||
var healthWithError = new DriverHealth(state, LastSuccessfulRead: DateTime.UtcNow, LastError: "earlier failure");
|
||||
var healthWithoutError = new DriverHealth(state, LastSuccessfulRead: DateTime.UtcNow, LastError: null);
|
||||
|
||||
// Both shapes are constructible regardless of state — the type makes no enforcement.
|
||||
healthWithError.LastError.ShouldBe("earlier failure");
|
||||
healthWithoutError.LastError.ShouldBeNull();
|
||||
healthWithError.State.ShouldBe(state);
|
||||
healthWithoutError.State.ShouldBe(state);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DriverState_EnumContainsExpectedMembers()
|
||||
{
|
||||
// Pins the enum so finding-008's "more than Healthy can carry an error" claim
|
||||
// does not bit-rot.
|
||||
var names = Enum.GetNames<DriverState>();
|
||||
names.ShouldContain(nameof(DriverState.Unknown));
|
||||
names.ShouldContain(nameof(DriverState.Initializing));
|
||||
names.ShouldContain(nameof(DriverState.Healthy));
|
||||
names.ShouldContain(nameof(DriverState.Degraded));
|
||||
names.ShouldContain(nameof(DriverState.Reconnecting));
|
||||
names.ShouldContain(nameof(DriverState.Faulted));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user