Files
lmxopcua/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Tests/FakeHistorianGatewayClient.cs
T

215 lines
7.9 KiB
C#

using System.Runtime.CompilerServices;
using ZB.MOM.WW.HistorianGateway.Contracts.Grpc;
namespace ZB.MOM.WW.OtOpcUa.Driver.Historian.Gateway.Tests;
/// <summary>
/// Reusable in-memory test double for <see cref="IHistorianGatewayClient"/>. Every method returns
/// from a public settable result field and records its call arguments into public fields, so the
/// later driver tasks (T7/T8/T11/T12/T14) can drive behaviour and assert on what the driver sent
/// without a live gateway. Throw fields let a test simulate transport faults (e.g. an
/// <c>RpcException</c>) per operation; reads share <see cref="ThrowOnRead"/>.
/// </summary>
public sealed class FakeHistorianGatewayClient : IHistorianGatewayClient
{
// ---- ReadRaw -------------------------------------------------------------------------------
public IReadOnlyList<HistorianSample> RawSamples = Array.Empty<HistorianSample>();
public string? LastReadRawTag;
public DateTime LastReadRawStartUtc;
public DateTime LastReadRawEndUtc;
public int LastReadRawMaxValues;
public int ReadRawCallCount;
// ---- ReadAggregate -------------------------------------------------------------------------
public IReadOnlyList<HistorianAggregateSample> AggregateSamples = Array.Empty<HistorianAggregateSample>();
public string? LastAggregateTag;
public DateTime LastAggregateStartUtc;
public DateTime LastAggregateEndUtc;
public RetrievalMode LastAggregateMode;
public TimeSpan LastAggregateInterval;
public int ReadAggregateCallCount;
// ---- ReadAtTime ----------------------------------------------------------------------------
public IReadOnlyList<HistorianSample> AtTimeSamples = Array.Empty<HistorianSample>();
public string? LastReadAtTimeTag;
public IReadOnlyList<DateTime>? LastReadAtTimeTimestamps;
public int ReadAtTimeCallCount;
// ---- ReadEvents ----------------------------------------------------------------------------
public IReadOnlyList<HistorianEvent> Events = Array.Empty<HistorianEvent>();
public string? LastReadEventsSourceName;
public DateTime LastReadEventsStartUtc;
public DateTime LastReadEventsEndUtc;
public int LastReadEventsMaxEvents;
public int ReadEventsCallCount;
/// <summary>Thrown (deferred to first enumeration) by every read method when set.</summary>
public Exception? ThrowOnRead;
// ---- WriteLiveValues -----------------------------------------------------------------------
public WriteAck WriteLiveValuesResult = new() { Success = true };
public string? LastWriteLiveTag;
public IReadOnlyList<HistorianLiveValue>? LastWriteLiveValues;
public int WriteLiveValuesCallCount;
public Exception? WriteLiveValuesThrows;
// ---- SendEvent -----------------------------------------------------------------------------
public WriteAck SendEventResult = new() { Success = true };
public HistorianEvent? LastSendEvent;
public int SendEventCallCount;
public Exception? SendEventThrows;
// ---- EnsureTags ----------------------------------------------------------------------------
public TagOperationResults EnsureTagsResult = new();
public IReadOnlyList<HistorianTagDefinition>? LastEnsureDefinitions;
public int EnsureTagsCallCount;
public Exception? EnsureTagsThrows;
// ---- Probe ---------------------------------------------------------------------------------
public bool ProbeResult = true;
public int ProbeCallCount;
public Exception? ProbeThrows;
// ---- GetConnectionStatus -------------------------------------------------------------------
public ConnectionStatus ConnectionStatus = new();
public int GetConnectionStatusCallCount;
public Exception? GetConnectionStatusThrows;
// ---- Dispose -------------------------------------------------------------------------------
public int DisposeCallCount;
public IAsyncEnumerable<HistorianSample> ReadRawAsync(
string tag,
DateTime startUtc,
DateTime endUtc,
int maxValues,
CancellationToken ct)
{
LastReadRawTag = tag;
LastReadRawStartUtc = startUtc;
LastReadRawEndUtc = endUtc;
LastReadRawMaxValues = maxValues;
ReadRawCallCount++;
return ToAsyncStream(RawSamples, ThrowOnRead, ct);
}
public IAsyncEnumerable<HistorianAggregateSample> ReadAggregateAsync(
string tag,
DateTime startUtc,
DateTime endUtc,
RetrievalMode mode,
TimeSpan interval,
CancellationToken ct)
{
LastAggregateTag = tag;
LastAggregateStartUtc = startUtc;
LastAggregateEndUtc = endUtc;
LastAggregateMode = mode;
LastAggregateInterval = interval;
ReadAggregateCallCount++;
return ToAsyncStream(AggregateSamples, ThrowOnRead, ct);
}
public Task<IReadOnlyList<HistorianSample>> ReadAtTimeAsync(
string tag,
IReadOnlyList<DateTime> timestampsUtc,
CancellationToken ct)
{
LastReadAtTimeTag = tag;
LastReadAtTimeTimestamps = timestampsUtc;
ReadAtTimeCallCount++;
return ThrowOnRead is not null
? Task.FromException<IReadOnlyList<HistorianSample>>(ThrowOnRead)
: Task.FromResult(AtTimeSamples);
}
public IAsyncEnumerable<HistorianEvent> ReadEventsAsync(
string? sourceName,
DateTime startUtc,
DateTime endUtc,
int maxEvents,
CancellationToken ct)
{
LastReadEventsSourceName = sourceName;
LastReadEventsStartUtc = startUtc;
LastReadEventsEndUtc = endUtc;
LastReadEventsMaxEvents = maxEvents;
ReadEventsCallCount++;
return ToAsyncStream(Events, ThrowOnRead, ct);
}
public Task<WriteAck> WriteLiveValuesAsync(
string tag,
IReadOnlyList<HistorianLiveValue> values,
CancellationToken ct)
{
LastWriteLiveTag = tag;
LastWriteLiveValues = values;
WriteLiveValuesCallCount++;
return WriteLiveValuesThrows is not null
? Task.FromException<WriteAck>(WriteLiveValuesThrows)
: Task.FromResult(WriteLiveValuesResult);
}
public Task<WriteAck> SendEventAsync(HistorianEvent evt, CancellationToken ct)
{
LastSendEvent = evt;
SendEventCallCount++;
return SendEventThrows is not null
? Task.FromException<WriteAck>(SendEventThrows)
: Task.FromResult(SendEventResult);
}
public Task<TagOperationResults> EnsureTagsAsync(
IReadOnlyList<HistorianTagDefinition> definitions,
CancellationToken ct)
{
LastEnsureDefinitions = definitions;
EnsureTagsCallCount++;
return EnsureTagsThrows is not null
? Task.FromException<TagOperationResults>(EnsureTagsThrows)
: Task.FromResult(EnsureTagsResult);
}
public Task<bool> ProbeAsync(CancellationToken ct)
{
ProbeCallCount++;
return ProbeThrows is not null
? Task.FromException<bool>(ProbeThrows)
: Task.FromResult(ProbeResult);
}
public Task<ConnectionStatus> GetConnectionStatusAsync(CancellationToken ct)
{
GetConnectionStatusCallCount++;
return GetConnectionStatusThrows is not null
? Task.FromException<ConnectionStatus>(GetConnectionStatusThrows)
: Task.FromResult(ConnectionStatus);
}
public ValueTask DisposeAsync()
{
DisposeCallCount++;
return ValueTask.CompletedTask;
}
private static async IAsyncEnumerable<T> ToAsyncStream<T>(
IReadOnlyList<T> items,
Exception? error,
[EnumeratorCancellation] CancellationToken ct)
{
if (error is not null)
{
throw error;
}
foreach (var item in items)
{
ct.ThrowIfCancellationRequested();
yield return item;
}
await Task.CompletedTask.ConfigureAwait(false);
}
}