Files
scadaproj/ZB.MOM.WW.SPHistorianClient/tests/ZB.MOM.WW.SPHistorianClient.Tests/HistorianGrpcTransportTests.cs
T

115 lines
4.7 KiB
C#

using ZB.MOM.WW.SPHistorianClient.Grpc;
using ZB.MOM.WW.SPHistorianClient.Models;
using ZB.MOM.WW.SPHistorianClient.Wcf;
using Google.Protobuf;
using ArchestrA.Grpc.Contract.Retrieval;
using GrpcHistory = ArchestrA.Grpc.Contract.History;
namespace ZB.MOM.WW.SPHistorianClient.Tests;
/// <summary>
/// Unit coverage for the 2023 R2 RemoteGrpc transport — the parts that do not require a live
/// server: channel address/port resolution, metadata, transport routing, and the invariant that
/// gRPC request messages carry the same native byte buffers the WCF path uses.
/// </summary>
public sealed class HistorianGrpcTransportTests
{
private static HistorianClientOptions Options(
string host = "histserver",
int port = HistorianClientOptions.DefaultPort,
bool tls = false,
string? dnsIdentity = null,
bool compression = false) => new()
{
Host = host,
Port = port,
Transport = HistorianTransport.RemoteGrpc,
GrpcUseTls = tls,
ServerDnsIdentity = dnsIdentity,
Compression = compression,
IntegratedSecurity = true
};
[Fact]
public void ResolvePort_DefaultWcfPort_SubstitutesGrpcDefault()
{
Assert.Equal(HistorianClientOptions.DefaultGrpcPort, HistorianGrpcChannelFactory.ResolvePort(Options(port: HistorianClientOptions.DefaultPort)));
}
[Fact]
public void ResolvePort_ExplicitPort_IsHonoured()
{
Assert.Equal(443, HistorianGrpcChannelFactory.ResolvePort(Options(port: 443)));
}
[Fact]
public void ResolveAddress_Plaintext_UsesHttpAndHost()
{
Assert.Equal("http://histserver:32565", HistorianGrpcChannelFactory.ResolveAddress(Options()));
}
[Fact]
public void ResolveAddress_Tls_UsesHttpsAndHostWhenNoDnsIdentity()
{
Assert.Equal("https://histserver:32565", HistorianGrpcChannelFactory.ResolveAddress(Options(tls: true)));
}
[Fact]
public void ResolveAddress_Tls_PrefersDnsIdentityForCertMatch()
{
string address = HistorianGrpcChannelFactory.ResolveAddress(Options(host: "10.0.0.5", tls: true, dnsIdentity: "localhost"));
Assert.Equal("https://localhost:32565", address);
}
[Fact]
public void Create_CompressionDisabled_EmitsNoEncodingHeader()
{
using HistorianGrpcConnection connection = HistorianGrpcChannelFactory.Create(Options(compression: false));
Assert.DoesNotContain(connection.Metadata, e => e.Key == "grpc-internal-encoding-request");
}
[Fact]
public void Create_CompressionEnabled_AdvertisesGzipRequestEncoding()
{
using HistorianGrpcConnection connection = HistorianGrpcChannelFactory.Create(Options(compression: true));
global::Grpc.Core.Metadata.Entry entry = Assert.Single(connection.Metadata, e => e.Key == "grpc-internal-encoding-request");
Assert.Equal("gzip", entry.Value);
}
[Fact]
public void StartQueryRequest_CarriesNativeDataQueryBufferUnchanged()
{
// The gRPC envelope must wrap the exact bytes the WCF StartQuery2 path sends, so the
// already-reverse-engineered DataQueryRequest serializer is reused verbatim.
HistorianDataQueryRequest request = HistorianWcfReadOrchestrator.BuildDataQueryRequest(
"Tag.Counter", new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc), new DateTime(2026, 1, 2, 0, 0, 0, DateTimeKind.Utc), 100);
byte[] nativeBuffer = HistorianDataQueryProtocol.SerializeFullHistoryRequest(request);
var message = new StartQueryRequest
{
UiHandle = 7,
UiQueryRequestType = HistorianDataQueryProtocol.QueryRequestTypeData,
BtRequestBuffer = ByteString.CopyFrom(nativeBuffer)
};
// Round-trip through protobuf and confirm the native buffer survives byte-for-byte.
byte[] wire = message.ToByteArray();
var decoded = StartQueryRequest.Parser.ParseFrom(wire);
Assert.Equal(nativeBuffer, decoded.BtRequestBuffer.ToByteArray());
Assert.Equal(7u, decoded.UiHandle);
Assert.Equal((uint)HistorianDataQueryProtocol.QueryRequestTypeData, decoded.UiQueryRequestType);
}
[Fact]
public void OpenConnectionRequest_CarriesNativeOpen2BufferUnchanged()
{
byte[] open2 = HistorianNativeHandshake.BuildOpenConnection3Request(
"histserver", Guid.NewGuid(), HistorianWcfAuthChainHelper.NativeIntegratedReadOnlyConnectionMode);
var message = new GrpcHistory.OpenConnectionRequest { BtConnectionRequest = ByteString.CopyFrom(open2) };
var decoded = GrpcHistory.OpenConnectionRequest.Parser.ParseFrom(message.ToByteArray());
Assert.Equal(open2, decoded.BtConnectionRequest.ToByteArray());
}
}