6d470eab4a
Roadmap M1 R1.7. Filters are set on the native EventQuery object via AddEventFilter(property, HistorianComparisionType, value) — NOT EventQueryArgs (time/count/order only). Found via a new harness --dump-type-members command. Captured the native filtered StartEventQuery pRequestBuff (Capture-EventFilter.ps1 + harness --event-filter knob) and diffed Equal(0) vs Contains(12) to isolate the operator field. Filter block (decoded byte-for-byte): ushort 0 + uint filterCount + uint condCount + uint nameLen + name(UTF-16) + uint 1 + ushort op + uint 1 + value(0x09-LEN-0x00 compact-ASCII) + byte 0 The filter is REAL, not inert (unlike the analog-summary knobs): a non-matching predicate returns 0 events; Type=Equal=User.Write returns only User.Write events. Verified live via both the native harness and the SDK. - HistorianClient.ReadEventsAsync(start, end, HistorianEventFilter, ct) overload - HistorianEventFilter + HistorianEventComparison (18 ops, ordinals = native) - Filter encoding in HistorianEventQueryProtocol (empty-filter path unchanged) - Golden-byte tests (block match, op field, empty-filter regression) + gated live test Single string-valued predicate only; multi-filter (OR) / multi-condition (AND via AddEventFilterCondition) framing is partially captured and not shipped. 216 unit tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B6mcaT2PjRFKcogzp9UkfC
64 lines
2.7 KiB
C#
64 lines
2.7 KiB
C#
using System.Runtime.Versioning;
|
|
using AVEVA.Historian.Client.Wcf;
|
|
using Xunit.Abstractions;
|
|
|
|
namespace AVEVA.Historian.Client.Tests;
|
|
|
|
[SupportedOSPlatform("windows")]
|
|
public sealed class EventChainDiagnosticTests
|
|
{
|
|
private readonly ITestOutputHelper _output;
|
|
|
|
public EventChainDiagnosticTests(ITestOutputHelper output)
|
|
{
|
|
_output = output;
|
|
}
|
|
|
|
[Fact]
|
|
public async Task EventOrchestrator_DiagnosticDump_AgainstLocalHistorian()
|
|
{
|
|
string? host = Environment.GetEnvironmentVariable("HISTORIAN_HOST");
|
|
if (string.IsNullOrWhiteSpace(host) || !string.Equals(host, "localhost", StringComparison.OrdinalIgnoreCase) || !OperatingSystem.IsWindows())
|
|
{
|
|
return;
|
|
}
|
|
|
|
HistorianClientOptions options = new()
|
|
{
|
|
Host = host,
|
|
IntegratedSecurity = true,
|
|
Transport = HistorianTransport.LocalPipe
|
|
};
|
|
|
|
HistorianWcfEventOrchestrator orchestrator = new(options);
|
|
DateTime endUtc = DateTime.UtcNow;
|
|
DateTime startUtc = endUtc - TimeSpan.FromDays(7);
|
|
|
|
int observed = 0;
|
|
AVEVA.Historian.Client.Models.HistorianEvent? firstEvent = null;
|
|
await foreach (var evt in orchestrator.ReadEventsAsync(startUtc, endUtc, filter: null, CancellationToken.None))
|
|
{
|
|
observed++;
|
|
firstEvent ??= evt;
|
|
}
|
|
|
|
_output.WriteLine($"Events observed: {observed}");
|
|
if (firstEvent is not null)
|
|
{
|
|
_output.WriteLine($" EventTimeUtc: {firstEvent.EventTimeUtc:O}");
|
|
_output.WriteLine($" ReceivedTimeUtc: {firstEvent.ReceivedTimeUtc:O}");
|
|
_output.WriteLine($" Type: {firstEvent.Type}");
|
|
_output.WriteLine($" Properties.Count:{firstEvent.Properties.Count}");
|
|
_output.WriteLine($" Has alarm_id: {firstEvent.Id != Guid.Empty}");
|
|
}
|
|
_output.WriteLine($"LastEnsT2Handle: {HistorianWcfEventOrchestrator.LastEnsT2Handle}");
|
|
_output.WriteLine($"LastEnsT2PayloadSha256: {HistorianWcfEventOrchestrator.LastEnsT2PayloadSha256}");
|
|
_output.WriteLine($"LastUpdC3ReturnCode: {HistorianWcfEventOrchestrator.LastUpdC3ReturnCode}");
|
|
_output.WriteLine($"LastRTag2ReturnCode: {HistorianWcfEventOrchestrator.LastRTag2ReturnCode}");
|
|
_output.WriteLine($"LastAddReturnCode (EnsT2): {HistorianWcfEventOrchestrator.LastAddReturnCode}");
|
|
_output.WriteLine($"LastAddOutputLength: {HistorianWcfEventOrchestrator.LastAddOutputLength}");
|
|
_output.WriteLine($"LastResultBufferLength: {orchestrator.LastResultBufferLength}");
|
|
_output.WriteLine($"LastErrorBufferDescription: {orchestrator.LastErrorBufferDescription}");
|
|
}
|
|
}
|