test(live): assert FU-1 alarm SendEvent->ReadEvents round-trip (gateway C4 fixed) #425
+13
-18
@@ -186,35 +186,30 @@ public sealed class GatewayLiveIntegrationTests(GatewayLiveFixture fixture) : IC
|
|||||||
HistorianWriteOutcome.Ack,
|
HistorianWriteOutcome.Ack,
|
||||||
"the alarm SendEvent must be acked — needs the gateway write scope (historian:write) and SendEvent path.");
|
"the alarm SendEvent must be acked — needs the gateway write scope (historian:write) and SendEvent path.");
|
||||||
|
|
||||||
// Read the event back over a recent window for the source. The SQL event write can lag, so poll.
|
// Read the event back over a recent window for the source. The SQL event write can lag (the
|
||||||
|
// live event view has variable flush latency), so poll generously.
|
||||||
await using var dataSource = _fx.CreateDataSource();
|
await using var dataSource = _fx.CreateDataSource();
|
||||||
IReadOnlyList<HistoricalEvent> events = Array.Empty<HistoricalEvent>();
|
IReadOnlyList<HistoricalEvent> events = Array.Empty<HistoricalEvent>();
|
||||||
var deadline = DateTime.UtcNow + TimeSpan.FromSeconds(15);
|
var deadline = DateTime.UtcNow + TimeSpan.FromSeconds(60);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
var read = await dataSource.ReadEventsAsync(
|
var read = await dataSource.ReadEventsAsync(
|
||||||
source, eventUtc - TimeSpan.FromMinutes(5), DateTime.UtcNow + TimeSpan.FromMinutes(1), maxEvents: 0, ct);
|
source, eventUtc - TimeSpan.FromMinutes(5), DateTime.UtcNow + TimeSpan.FromMinutes(1), maxEvents: 0, ct);
|
||||||
events = read.Events;
|
events = read.Events;
|
||||||
if (events.Count > 0) break;
|
if (events.Count > 0) break;
|
||||||
await Task.Delay(TimeSpan.FromSeconds(1), ct);
|
await Task.Delay(TimeSpan.FromSeconds(2), ct);
|
||||||
}
|
}
|
||||||
while (DateTime.UtcNow < deadline);
|
while (DateTime.UtcNow < deadline);
|
||||||
|
|
||||||
// The SendEvent itself is the OtOpcUa contract and is asserted above. The source-filtered
|
// The source-filtered READBACK of OtOpcUa's own just-sent alarm now round-trips: the gateway
|
||||||
// READBACK of a just-sent event is a historian/gateway property, not an OtOpcUa one: verified
|
// threads the wire event's SourceName into the `source_object` event property, so an ad-hoc
|
||||||
// live, the gateway's SQL event reader works and source-filtering works for events that carry a
|
// SendEvent is recorded in dbo.Events WITH a Source_Object and a source-filtered ReadEvents
|
||||||
// Source_Object (real Galaxy-sourced events read back by source correctly), but an ad-hoc
|
// finds it (gateway C4 fix, 2026-06-27; pending.md C4 / histsdk #3). Previously this branch
|
||||||
// SendEvent is recorded in dbo.Events WITHOUT a Source_Object — so a source-filtered read of a
|
// skipped because ad-hoc sends landed with Source_Object=NULL; that limitation is now closed,
|
||||||
// freshly-sent event finds nothing. Reading existing Galaxy alarm/event history by source works;
|
// so the round-trip is asserted.
|
||||||
// round-tripping OtOpcUa's OWN sends by source needs the gateway's SendEvent to populate the
|
events.ShouldNotBeEmpty(
|
||||||
// event source. So when no event comes back, skip with that reason rather than failing.
|
$"a source-filtered ReadEvents must return the just-sent alarm for source '{source}': the gateway now " +
|
||||||
if (events.Count == 0)
|
"populates Source_Object from the event SourceName (C4 fix), so OtOpcUa's own alarm sends round-trip.");
|
||||||
{
|
|
||||||
Assert.Skip(
|
|
||||||
$"Send acked, but a source-filtered ReadEvents returned 0 for source '{source}'. The SQL event " +
|
|
||||||
"reader works (Galaxy-sourced events read back by source); an ad-hoc SendEvent is stored without " +
|
|
||||||
"a Source_Object, so its source-filtered readback is empty until the gateway populates the event source.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var exactMatch = events.Any(e => string.Equals(e.EventId, alarmId, StringComparison.Ordinal));
|
var exactMatch = events.Any(e => string.Equals(e.EventId, alarmId, StringComparison.Ordinal));
|
||||||
TestContext.Current.SendDiagnosticMessage(
|
TestContext.Current.SendDiagnosticMessage(
|
||||||
|
|||||||
Reference in New Issue
Block a user