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
This commit is contained in:
+67
@@ -0,0 +1,67 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user