From 7d5aeaeb0647e2b24515ce0f9bae41bf9bc3cb3d Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Fri, 19 Jun 2026 15:12:41 -0400 Subject: [PATCH] Strengthen live event-read test: assert well-formed parsed events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ReadEventsAsync verified to return real, parsed events against the local 2020 server (e.g. User.Write with 18 properties) — the row parser (HistorianEventRowProtocol v9) is wired and works. The prior test only asserted NotNull with a stale "row format not yet decoded" comment. - Renamed to ReadEventsAsync_AgainstLocalHistorian_ReturnsWellFormedEvents. - Widened the window to 30 days (robust against a quiet recent window). - Asserts NotEmpty + per-event well-formedness (non-empty Type, non-null Properties, EventTimeUtc within the queried window) — matching the ReadRawAsync test's NotEmpty style. - Documents the known limitation: enumeration stops at the first benign `type=4 code=85` soft-terminal, so this verifies parsing correctness rather than exhaustive retrieval (draining all rows needs the code-85 decode, a capture task). Passes live (1 event over 30 days). Non-live unit suite unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../HistorianClientIntegrationTests.cs | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/tests/AVEVA.Historian.Client.Tests/HistorianClientIntegrationTests.cs b/tests/AVEVA.Historian.Client.Tests/HistorianClientIntegrationTests.cs index f906675..be7e6ac 100644 --- a/tests/AVEVA.Historian.Client.Tests/HistorianClientIntegrationTests.cs +++ b/tests/AVEVA.Historian.Client.Tests/HistorianClientIntegrationTests.cs @@ -211,7 +211,7 @@ public sealed class HistorianClientIntegrationTests } [Fact] - public async Task ReadEventsAsync_AgainstLocalHistorian_DoesNotThrow() + public async Task ReadEventsAsync_AgainstLocalHistorian_ReturnsWellFormedEvents() { string? host = Environment.GetEnvironmentVariable("HISTORIAN_HOST"); if (string.IsNullOrWhiteSpace(host) || !string.Equals(host, "localhost", StringComparison.OrdinalIgnoreCase) || !OperatingSystem.IsWindows()) @@ -227,18 +227,28 @@ public sealed class HistorianClientIntegrationTests }); DateTime endUtc = DateTime.UtcNow; - DateTime startUtc = endUtc - TimeSpan.FromDays(7); + DateTime startUtc = endUtc - TimeSpan.FromDays(30); - // The event-row WCF wire format is not yet decoded; this test verifies the chain - // (ValCl + Open2 + Retr.IsOriginalAllowed + Retr.StartEventQuery) reaches the server - // without throwing. An empty event list is acceptable until row parsing is wired. + // The full chain (ValCl + Open2 + Retr.IsOriginalAllowed + Retr.StartEventQuery + + // GetNextEventQueryResultBuffer + HistorianEventRowProtocol.Parse) returns real, parsed + // events. Requires the local store to hold events in the window — System-Platform + // alarm/user-write events are present on a working Historian. NOTE: enumeration currently + // stops at the first benign `type=4 code=85` soft-terminal, so this verifies parsing + // correctness rather than exhaustive retrieval (decoding code 85 to drain all rows is a + // separate capture task). List events = []; await foreach (AVEVA.Historian.Client.Models.HistorianEvent evt in client.ReadEventsAsync(startUtc, endUtc, CancellationToken.None)) { events.Add(evt); } - Assert.NotNull(events); + Assert.NotEmpty(events); + Assert.All(events, evt => + { + Assert.False(string.IsNullOrWhiteSpace(evt.Type)); // e.g. "User.Write", "Alarm.Set" + Assert.NotNull(evt.Properties); + Assert.InRange(evt.EventTimeUtc, startUtc - TimeSpan.FromDays(1), endUtc + TimeSpan.FromDays(1)); + }); } [Fact]