Files
lmxopcua/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Sql.Common.Tests/SharedHelperTests.cs
T
Joseph Doherty f0700571e8 test(historian): direct Sql.Common evaluator tests (1b)
51 new test cases (34 methods) in Sql.Common.Tests covering AtTimeEvaluator, AggregateEvaluator
(hand-built tag-A bucket rows, ProcessedRead literals), BucketPlan, LiveWritePreparer and
HistoryUpdatePlanner (incl. resolutionTicks=10 truncate-before-dedup and the superseded-duplicate
outcome), plus EventContinuation, HistorianHealthCounters, ClampSeverity and StoredSample.FromStored.
Each was falsified by reverting the rule it pins (37 mutations, all red, all restored).

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
2026-10-11 01:35:51 -04:00

68 lines
2.8 KiB
C#

using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
namespace ZB.MOM.WW.OtOpcUa.Driver.Historian.Sql.Common.Tests;
/// <summary>EventContinuation, HistorianHealthCounters, ClampSeverity and the StoredSample quality clamp.</summary>
public sealed class SharedHelperTests
{
[Fact]
public void Event_continuation_is_ticks_pipe_event_id()
{
var t = new DateTime(2026, 10, 9, 8, 0, 0, DateTimeKind.Utc).AddTicks(1234567);
EventContinuation.Encode(t, "abc").ShouldBe($"{t.Ticks.ToString(System.Globalization.CultureInfo.InvariantCulture)}|abc");
EventContinuation.Encode(new DateTime(42), "id").ShouldBe("42|id");
}
[Theory]
[InlineData(-5, 0)]
[InlineData(700, 700)]
[InlineData(70_000, 65_535)]
public void Event_severity_is_clamped_to_ushort(int stored, int expected) =>
HistoricalEventRows.ClampSeverity(stored).ShouldBe((ushort)expected);
[Fact]
public void Health_counters_open_only_after_a_success_with_no_failure_since()
{
var h = new HistorianHealthCounters();
h.Snapshot().ProcessConnectionOpen.ShouldBeFalse();
h.RecordSuccess();
h.Snapshot().ProcessConnectionOpen.ShouldBeTrue();
h.RecordFailure(new InvalidOperationException("boom"));
var s = h.Snapshot();
s.ProcessConnectionOpen.ShouldBeFalse();
s.EventConnectionOpen.ShouldBeFalse();
s.ConsecutiveFailures.ShouldBe(1);
s.TotalQueries.ShouldBe(2);
s.LastError.ShouldBe("InvalidOperationException: boom");
h.RecordSuccess();
h.Snapshot().ConsecutiveFailures.ShouldBe(0);
h.Snapshot().ProcessConnectionOpen.ShouldBeTrue();
}
[Fact]
public void A_cancellation_is_not_a_health_failure()
{
var h = new HistorianHealthCounters();
h.RecordFailure(new OperationCanceledException());
h.RecordFailure(new TaskCanceledException());
var s = h.Snapshot();
s.TotalQueries.ShouldBe(0);
s.TotalFailures.ShouldBe(0);
s.LastError.ShouldBeNull();
}
[Fact]
public void A_stored_empty_sample_with_a_non_bad_status_is_served_BadNoData()
{
var t = DateTime.UnixEpoch;
StoredSample.FromStored(t, HistorianValue.Empty, 0u).Status.ShouldBe(0x809B0000u);
StoredSample.FromStored(t, HistorianValue.Empty, 0x40000000u).Status.ShouldBe(0x809B0000u);
StoredSample.FromStored(t, HistorianValue.Empty, 0x80310000u).Status.ShouldBe(0x80310000u);
StoredSample.FromStored(t, HistorianValue.FromDouble(1), 0x40000000u).Status.ShouldBe(0x40000000u);
StoredSample.FromStored(t, HistorianValue.Empty, 0x80310000u).IsUsable.ShouldBeFalse();
StoredSample.FromStored(t, HistorianValue.FromDouble(1), 0x40000000u).IsGood.ShouldBeFalse();
}
}