7a3cd9b76e
DelT and EnsT2 had two distinct silent-fail blockers; both now resolved live end-to-end. Read path's RetrievalMode mapping was missing 11 of 15 enum values (plus a latent Cyclic→4 bug). Investigation tooling kept as env-gated helpers. DelT silent fail: Open2 was using NativeIntegratedReadOnlyConnectionMode (0x402); server returned err 132 OperationNotEnabled silently. Added NativeIntegratedWriteEnabledConnectionMode (0x401) per HistorianAccessUtil.SetConnectionMode bit map (Process=1 | IntegratedSecurity=0x400). Write orchestrator now opens with write-enabled mode. EnsT2 silent fail: byte-by-byte comparison via inspector revealed two bugs in SerializeAnalogCTagMetadata. The original "146-byte byte-for-byte match" was misaligned — it omitted the leading 0x4E marker byte and treated WCF's `01 01 01` EndElement closing markers as if they were part of the InBuff payload. Real native InBuff is 144 bytes with 0x4E lead and 2-byte `FE 00` trailer. Golden test bytes corrected. EnsureTagAsync expansion: probed every analog data type via instrument-wcf-writemessage; byte 11 of CTagMetadata is the data-type discriminator (Float=0x01, Double=0x21, UInt2=0x09, UInt4=0x11, Int2=0x29, Int4=0x31). String/Int1/Int8/UInt8 fail at native AddTag — out of scope for this op. Range encoding decoded: defaults emit compact `1A 03`; non-default emit `1F 00` + 4 doubles in order MinEU/MaxEU/MinRaw/MaxRaw. MinRaw/MaxRaw sent on the wire but server mirrors them to MinEU/MaxEU when ApplyScaling=false (verified against native — server quirk, not SDK bug). RetrievalMode mapping: probed all 15 enum values; QueryType is just the native enum ordinal. Replaced the broken switch with `(uint)mode`. Existing SDK mapped Cyclic→4 (BestFit's value); Cyclic is actually 0. CLAUDE.md updated: stale "Active Protocol Blocker" rewritten as resolved-status block; SDK surface now reflects the read-blocker resolution and the new write ops; "Remaining gaps" punch list refreshed. Tools added (both env-gated, no runtime overhead unless flipped on): - HistorianWcfMessageCaptureBehavior — captures all WCF body bytes when AVEVA_HISTORIAN_SDK_WIRE_CAPTURE is set; used for byte-level diff vs native. - HistorianWcfHistAddressingBehavior — explicitly sets wsa:To header on the Hist channel for parity with native bytes (kept though not load-bearing). - WriteDiag in TagWriteOrchestrator — env-gated EnsT2/DelT response logging (AVEVA_HISTORIAN_DELT_DIAG). NativeTraceHarness CLI: added --write-min-eu/--write-max-eu/--write-min-raw/ --write-max-raw for capturing non-default-range EnsT2 payloads. Tests: 130 → 161 passing (+31). Includes 16-mode RetrievalMode mapping table, 4 per-data-type EnsT2 golden tests, NonDefaultRanges golden test, 6 live round-trip integration tests covering Float/Double/Int2/Int4/UInt4/FloatRanges, 3 live tests for previously-unmapped RetrievalMode values. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
41 lines
1.6 KiB
C#
41 lines
1.6 KiB
C#
using System.Runtime.Versioning;
|
|
using AVEVA.Historian.Client.Models;
|
|
using AVEVA.Historian.Client.Wcf;
|
|
|
|
namespace AVEVA.Historian.Client.Tests;
|
|
|
|
[SupportedOSPlatform("windows")]
|
|
public sealed class HistorianRetrievalModeMappingTests
|
|
{
|
|
// Probed 2026-05-04 via instrument-wcf-writemessage against every
|
|
// ArchestrA.HistorianRetrievalMode value — see HistorianWcfReadOrchestrator
|
|
// MapRetrievalModeToQueryType doc comment for capture details.
|
|
[Theory]
|
|
[InlineData(RetrievalMode.Cyclic, 0u)]
|
|
[InlineData(RetrievalMode.Delta, 1u)]
|
|
[InlineData(RetrievalMode.Full, 2u)]
|
|
[InlineData(RetrievalMode.Interpolated, 3u)]
|
|
[InlineData(RetrievalMode.BestFit, 4u)]
|
|
[InlineData(RetrievalMode.TimeWeightedAverage, 5u)]
|
|
[InlineData(RetrievalMode.MinimumWithTime, 6u)]
|
|
[InlineData(RetrievalMode.MaximumWithTime, 7u)]
|
|
[InlineData(RetrievalMode.Integral, 8u)]
|
|
[InlineData(RetrievalMode.Slope, 9u)]
|
|
[InlineData(RetrievalMode.Counter, 10u)]
|
|
[InlineData(RetrievalMode.ValueState, 11u)]
|
|
[InlineData(RetrievalMode.RoundTrip, 12u)]
|
|
[InlineData(RetrievalMode.StartBound, 13u)]
|
|
[InlineData(RetrievalMode.EndBound, 14u)]
|
|
public void MapRetrievalModeToQueryType_MatchesNativeEnumOrdinal(RetrievalMode mode, uint expectedQueryType)
|
|
{
|
|
Assert.Equal(expectedQueryType, HistorianWcfReadOrchestrator.MapRetrievalModeToQueryType(mode));
|
|
}
|
|
|
|
[Fact]
|
|
public void MapRetrievalModeToQueryType_UndefinedValue_Throws()
|
|
{
|
|
Assert.Throws<ProtocolEvidenceMissingException>(
|
|
() => HistorianWcfReadOrchestrator.MapRetrievalModeToQueryType((RetrievalMode)999));
|
|
}
|
|
}
|