b40e6948e2
Implemented HistorianWcfRevisionOrchestrator that talks WCF directly to /Trx, bypassing the native wrapper entirely. Probes AddNonStreamValuesBegin2 against the live local Historian and surfaces what the server returns. Internal-only API; no public surface added — the path isn't viable yet. Findings (live test against localhost): - ✅ The wire path is reachable. After moving from V1 (uint handle, no errorBuffer) to V2 (string handle GUID, out errorBuffer), the server recognizes the call (no ContractFilter mismatch, no exception). - ✅ Server processes the call and returns a structured 5-byte error buffer: 04 33 00 00 00 = type 4 (CustomError) + code 51 (UnknownClient). - ❌ Tried four handle formats (contextKey upper/lower, storageSessionId upper, ClientHandle as decimal string) — all return the same UnknownClient. - ❌ Adding the full priming chain (Stat.GetV ×2, Stat.GETHI ×2, UpdC3, 6× Stat.GetSystemParameter, AllowRenameTags, Trx.GetV, Stat.GetV, Retr.GetV) — same result. ITransactionServiceContract2 has no Validate/Register/Open op of its own. The client-with-Trx registration must happen via some cross- service side effect we haven't isolated. Important takeaway: the wire-format mismatch is solved (contract method names + parameter shapes match what the server expects). The remaining gap is a single missing initialization step. Documented in docs/plans/revision-write-path.md as concrete next-session steps. 178/178 tests pass (one new probe test added). Probe is gated on HISTORIAN_HOST=localhost. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
61 lines
2.6 KiB
C#
61 lines
2.6 KiB
C#
using System.Runtime.Versioning;
|
|
using AVEVA.Historian.Client;
|
|
using AVEVA.Historian.Client.Models;
|
|
using AVEVA.Historian.Client.Wcf;
|
|
using Xunit.Abstractions;
|
|
|
|
namespace AVEVA.Historian.Client.Tests;
|
|
|
|
/// <remarks>
|
|
/// Probes the SDK-direct WCF revision-write path (D2 new path). Calls
|
|
/// <c>AddNonStreamValuesBegin</c> through <see cref="HistorianWcfRevisionOrchestrator"/>
|
|
/// against the live local Historian and surfaces what the server returns. The
|
|
/// underlying native wrapper is gated client-side by err 129 TagNotFoundInCache;
|
|
/// this test bypasses the wrapper entirely and asks the SERVER directly. Gated on
|
|
/// HISTORIAN_HOST=localhost; skips otherwise.
|
|
/// </remarks>
|
|
[SupportedOSPlatform("windows")]
|
|
public sealed class HistorianWcfRevisionProbeTests
|
|
{
|
|
private readonly ITestOutputHelper _output;
|
|
|
|
public HistorianWcfRevisionProbeTests(ITestOutputHelper output)
|
|
{
|
|
_output = output;
|
|
}
|
|
|
|
[Fact]
|
|
public async Task AddNonStreamValuesBegin_ProbeReturnsServerResult()
|
|
{
|
|
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,
|
|
};
|
|
|
|
HistorianWcfRevisionOrchestrator orchestrator = new(options);
|
|
HistorianRevisionProbeResult result = await orchestrator.ProbeBeginAsync(CancellationToken.None);
|
|
|
|
_output.WriteLine($"OpenSucceeded: {result.OpenSucceeded}");
|
|
_output.WriteLine($"ClientHandle: {result.ClientHandle}");
|
|
_output.WriteLine($"StorageSessionId: {result.StorageSessionId}");
|
|
_output.WriteLine($"TrxInterfaceVersion: {result.TrxInterfaceVersion} (rc={result.TrxInterfaceVersionReturnCode}) ex={result.TrxInterfaceVersionException}");
|
|
_output.WriteLine($"BeginSucceeded: {result.BeginSucceeded}");
|
|
_output.WriteLine($"BeginTransactionId: {result.BeginTransactionId}");
|
|
foreach (HistorianRevisionBeginAttempt attempt in result.BeginAttempts)
|
|
{
|
|
_output.WriteLine($" attempt[{attempt.HandleLabel}] handle={attempt.HandleSent} ok={attempt.Succeeded} tx={attempt.TransactionId} err={attempt.ErrorHex} ex={attempt.Exception}");
|
|
}
|
|
|
|
Assert.True(result.OpenSucceeded, "Auth chain failed; revision probe never reached the Trx endpoint.");
|
|
// Don't assert BeginSucceeded — we're surfacing whatever the server says, not requiring success.
|
|
}
|
|
}
|