Files
histsdk/tests/AVEVA.Historian.Client.Tests/WcfEvidenceTests.cs
T
dohertj2 c95824a65d Initial commit: managed .NET 10 AVEVA Historian SDK + reverse-engineering toolkit
Full read-only SDK (src/AVEVA.Historian.Client) implementing the CLAUDE.md required
surface against AVEVA Historian's binary WCF protocol — no native AVEVA runtime
dependency. All operations live-verified against a local Historian:

- ProbeAsync, ReadRawAsync, ReadAggregateAsync, ReadAtTimeAsync, ReadEventsAsync
- BrowseTagNamesAsync, GetTagMetadataAsync (17 native data-type codes mapped)
- GetConnectionStatusAsync, GetStoreForwardStatusAsync, GetSystemParameterAsync
- 108/108 unit + integration tests pass

Includes the reverse-engineering toolkit (tools/AVEVA.Historian.ReverseEngineering)
used to decode the protocol: WCF probes, IL inspection via dnlib, and IL-rewrite
instrumentation (instrument-wcf-{write,read}message etc.) plus the .NET Framework
trace harness (tools/AVEVA.Historian.NativeTraceHarness) for parity testing.

Sanitized handoff evidence under docs/reverse-engineering/. Native AVEVA binaries
(current/, aveva-install-x64/, aveva-install-x86/) are gitignored — fetch separately
from the AVEVA installer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 06:31:48 -04:00

106 lines
5.4 KiB
C#

using System.Reflection;
using System.ServiceModel;
using AVEVA.Historian.Client.Wcf;
using AVEVA.Historian.Client.Wcf.Contracts;
namespace AVEVA.Historian.Client.Tests;
public sealed class WcfEvidenceTests
{
[Fact]
public void ServiceContractsUseDecompiledNamesAndNamespace()
{
AssertServiceContract<IHistoryServiceContract>("Hist");
AssertServiceContract<IHistoryServiceContract2>("Hist");
AssertServiceContract<IRetrievalServiceContract>("Retr");
AssertServiceContract<IRetrievalServiceContract4>("Retr");
AssertServiceContract<IStatusServiceContract>("Stat");
AssertServiceContract<IStatusServiceContract2>("Stat");
AssertServiceContract<IStorageServiceContract>("Storage");
AssertServiceContract<ITransactionServiceContract>("Trx");
}
[Fact]
public void RelayEvidenceIdentifiesHistorySecurityEndpointNames()
{
Assert.Equal("HistCert", HistorianWcfServiceNames.HistoryCertificate);
Assert.Equal("Hist-Integrated", HistorianWcfServiceNames.HistoryIntegrated);
}
[Fact]
public void KnownOperationAliasesMatchManagedWrapperEvidence()
{
AssertOperation<IHistoryServiceContract>(nameof(IHistoryServiceContract.GetInterfaceVersion), "GetV");
AssertOperation<IHistoryServiceContract>(nameof(IHistoryServiceContract.OpenConnection), "Open");
AssertOperation<IHistoryServiceContract>(nameof(IHistoryServiceContract.ValidateClient), "VldC");
AssertOperation<IHistoryServiceContract>(nameof(IHistoryServiceContract.UpdateClientStatus), "UpdC");
AssertOperation<IHistoryServiceContract2>(nameof(IHistoryServiceContract2.OpenConnection2), "Open2");
AssertOperation<IHistoryServiceContract2>(nameof(IHistoryServiceContract2.ExchangeKey), "ExKey");
AssertOperation<IRetrievalServiceContract2>(nameof(IRetrievalServiceContract2.GetTagInfosFromId), "GetTg");
AssertOperation<IRetrievalServiceContract3>(nameof(IRetrievalServiceContract3.StartTagQuery), "QTB");
AssertOperation<IRetrievalServiceContract4>(nameof(IRetrievalServiceContract4.GetTagExtendedPropertiesFromName), "GetTepByNm");
AssertOperation<IStorageServiceContract>(nameof(IStorageServiceContract.OpenStorageConnection), "Open");
AssertOperation<IStorageServiceContract>(nameof(IStorageServiceContract.LoadBlocks), "LoadB");
AssertOperation<ITransactionServiceContract>(nameof(ITransactionServiceContract.GetInterfaceVersion), "GetV");
AssertDefaultOperation<IRetrievalServiceContract>(nameof(IRetrievalServiceContract.StartQuery));
AssertDefaultOperation<IRetrievalServiceContract4>(nameof(IRetrievalServiceContract4.StartEventQuery));
AssertDefaultOperation<IStatusServiceContract>(nameof(IStatusServiceContract.GetServerTime));
AssertDefaultOperation<IStatusServiceContract2>(nameof(IStatusServiceContract2.GetSystemParameter));
AssertOperation<IStatusServiceContract2>(nameof(IStatusServiceContract2.GetHistorianInfo), "GETHI");
AssertOperation<IStatusServiceContract2>(nameof(IStatusServiceContract2.PingServer), "PNGS");
AssertOperation<IStatusServiceContract2>(nameof(IStatusServiceContract2.PingPipe), "PNGP");
}
[Fact]
public void MdasBindingUsesNetTcpAndCustomContentType()
{
var binding = HistorianWcfBindingFactory.CreateMdasNetTcpBinding(TimeSpan.FromSeconds(5));
var encoder = binding.CreateBindingElements().Find<MdasMessageEncodingBindingElement>();
var endpoint = HistorianWcfBindingFactory.CreateEndpointAddress("localhost", HistorianWcfBindingFactory.DefaultPort, HistorianWcfServiceNames.History);
Assert.NotNull(encoder);
Assert.Equal("net.tcp://localhost:32568/Hist", endpoint.Uri.AbsoluteUri);
Assert.Equal(MdasMessageEncoder.MdasContentType, encoder.CreateMessageEncoderFactory().Encoder.ContentType);
}
[Fact]
public void CertificateBindingUsesMdasEncodingOverTransportSecurity()
{
var binding = HistorianWcfBindingFactory.CreateMdasNetTcpCertificateBinding(TimeSpan.FromSeconds(5));
var elements = binding.CreateBindingElements();
var encoder = elements.Find<MdasMessageEncodingBindingElement>();
var security = elements.Find<System.ServiceModel.Channels.SslStreamSecurityBindingElement>();
Assert.NotNull(encoder);
Assert.NotNull(security);
Assert.Equal(MdasMessageEncoder.MdasContentType, encoder.CreateMessageEncoderFactory().Encoder.ContentType);
}
private static void AssertServiceContract<TContract>(string name)
{
var attribute = typeof(TContract).GetCustomAttribute<ServiceContractAttribute>();
Assert.NotNull(attribute);
Assert.Equal(name, attribute.Name);
Assert.Equal("aa", attribute.Namespace);
}
private static void AssertOperation<TContract>(string methodName, string operationName)
{
var method = typeof(TContract).GetMethod(methodName);
var attribute = method?.GetCustomAttribute<OperationContractAttribute>();
Assert.NotNull(attribute);
Assert.Equal(operationName, attribute.Name);
}
private static void AssertDefaultOperation<TContract>(string methodName)
{
var method = typeof(TContract).GetMethod(methodName);
var attribute = method?.GetCustomAttribute<OperationContractAttribute>();
Assert.NotNull(attribute);
Assert.Null(attribute.Name);
}
}