using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Proxy; using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Shared.Contracts; namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Proxy.Tests; /// /// Pins — the wire-to-domain mapping /// from (MessagePack-annotated IPC contract, /// Unix-ms timestamps) to Core.Abstractions.HistoricalEvent (domain record, /// timestamps). Added in PR 35 alongside the new /// IHistoryProvider.ReadEventsAsync method. /// [Trait("Category", "Unit")] public sealed class HistoricalEventMappingTests { [Fact] public void Maps_every_field_from_wire_to_domain_record() { var wire = new GalaxyHistoricalEvent { EventId = "evt-42", SourceName = "Tank1.HiAlarm", EventTimeUtcUnixMs = 1_700_000_000_000L, // 2023-11-14T22:13:20.000Z ReceivedTimeUtcUnixMs = 1_700_000_000_500L, DisplayText = "High level reached", Severity = 750, }; var domain = GalaxyProxyDriver.ToHistoricalEvent(wire); domain.EventId.ShouldBe("evt-42"); domain.SourceName.ShouldBe("Tank1.HiAlarm"); domain.EventTimeUtc.ShouldBe(new DateTime(2023, 11, 14, 22, 13, 20, DateTimeKind.Utc)); domain.ReceivedTimeUtc.ShouldBe(new DateTime(2023, 11, 14, 22, 13, 20, 500, DateTimeKind.Utc)); domain.Message.ShouldBe("High level reached"); domain.Severity.ShouldBe((ushort)750); } [Fact] public void Preserves_null_SourceName_and_DisplayText() { // Historical rows from the Galaxy event historian often omit source or message for // system events (e.g. time sync). The mapping must preserve null — callers use it to // distinguish system events from alarm events. var wire = new GalaxyHistoricalEvent { EventId = "sys-1", SourceName = null, EventTimeUtcUnixMs = 0, ReceivedTimeUtcUnixMs = 0, DisplayText = null, Severity = 1, }; var domain = GalaxyProxyDriver.ToHistoricalEvent(wire); domain.SourceName.ShouldBeNull(); domain.Message.ShouldBeNull(); } [Fact] public void EventTime_and_ReceivedTime_are_produced_as_DateTimeKind_Utc() { // Unix-ms timestamps come off the wire timezone-agnostic; the mapping must tag the // resulting DateTime as Utc so downstream serializers (JSON, OPC UA types) don't apply // an unexpected local-time offset. var wire = new GalaxyHistoricalEvent { EventId = "e", EventTimeUtcUnixMs = 1_000L, ReceivedTimeUtcUnixMs = 2_000L, }; var domain = GalaxyProxyDriver.ToHistoricalEvent(wire); domain.EventTimeUtc.Kind.ShouldBe(DateTimeKind.Utc); domain.ReceivedTimeUtc.Kind.ShouldBe(DateTimeKind.Utc); } }