92 lines
4.0 KiB
C#
92 lines
4.0 KiB
C#
using Opc.Ua;
|
|
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests;
|
|
|
|
[Trait("Category", "Unit")]
|
|
public sealed class OpcUaClientHistoryTests
|
|
{
|
|
[Theory]
|
|
[InlineData(HistoryAggregateType.Average)]
|
|
[InlineData(HistoryAggregateType.Minimum)]
|
|
[InlineData(HistoryAggregateType.Maximum)]
|
|
[InlineData(HistoryAggregateType.Total)]
|
|
[InlineData(HistoryAggregateType.Count)]
|
|
public void MapAggregateToNodeId_returns_standard_Part13_aggregate_for_every_enum(HistoryAggregateType agg)
|
|
{
|
|
var nodeId = OpcUaClientDriver.MapAggregateToNodeId(agg);
|
|
NodeId.IsNull(nodeId).ShouldBeFalse();
|
|
// Every mapping should resolve to an AggregateFunction_* NodeId (namespace 0, numeric id).
|
|
nodeId.NamespaceIndex.ShouldBe((ushort)0);
|
|
}
|
|
|
|
[Fact]
|
|
public void MapAggregateToNodeId_rejects_invalid_enum_value()
|
|
{
|
|
// Defense-in-depth: a future HistoryAggregateType addition mustn't silently fall through.
|
|
Should.Throw<ArgumentOutOfRangeException>(() =>
|
|
OpcUaClientDriver.MapAggregateToNodeId((HistoryAggregateType)99));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReadRawAsync_without_initialize_throws_InvalidOperationException()
|
|
{
|
|
using var drv = new OpcUaClientDriver(new OpcUaClientDriverOptions(), "opcua-hist-uninit");
|
|
await Should.ThrowAsync<InvalidOperationException>(async () =>
|
|
await drv.ReadRawAsync("ns=2;s=Counter",
|
|
DateTime.UtcNow.AddMinutes(-5), DateTime.UtcNow, 1000,
|
|
TestContext.Current.CancellationToken));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReadRawAsync_with_malformed_NodeId_returns_empty_result_not_throw()
|
|
{
|
|
// Same defensive pattern as ReadAsync / WriteAsync — malformed NodeId short-circuits
|
|
// to an empty result rather than crashing a batch history call. Needs init via the
|
|
// throw path first, then we pass "" to trigger the parse-fail branch inside
|
|
// ExecuteHistoryReadAsync. The init itself fails against 127.0.0.1:1 so we stop there.
|
|
// Not runnable without init — keep as placeholder for when the in-process fixture
|
|
// PR lands.
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReadProcessedAsync_without_initialize_throws_InvalidOperationException()
|
|
{
|
|
using var drv = new OpcUaClientDriver(new OpcUaClientDriverOptions(), "opcua-hist-uninit");
|
|
await Should.ThrowAsync<InvalidOperationException>(async () =>
|
|
await drv.ReadProcessedAsync("ns=2;s=Counter",
|
|
DateTime.UtcNow.AddMinutes(-5), DateTime.UtcNow,
|
|
TimeSpan.FromSeconds(10), HistoryAggregateType.Average,
|
|
TestContext.Current.CancellationToken));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReadAtTimeAsync_without_initialize_throws_InvalidOperationException()
|
|
{
|
|
using var drv = new OpcUaClientDriver(new OpcUaClientDriverOptions(), "opcua-hist-uninit");
|
|
await Should.ThrowAsync<InvalidOperationException>(async () =>
|
|
await drv.ReadAtTimeAsync("ns=2;s=Counter",
|
|
[DateTime.UtcNow.AddMinutes(-5), DateTime.UtcNow],
|
|
TestContext.Current.CancellationToken));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReadEventsAsync_throws_NotSupportedException_as_documented()
|
|
{
|
|
// The IHistoryProvider default implementation throws; the OPC UA Client driver
|
|
// deliberately inherits that default (see PR 76 commit body) because the OPC UA
|
|
// client call path needs an EventFilter SelectClauses spec the interface doesn't carry.
|
|
using var drv = new OpcUaClientDriver(new OpcUaClientDriverOptions(), "opcua-events-default");
|
|
await Should.ThrowAsync<NotSupportedException>(async () =>
|
|
await ((IHistoryProvider)drv).ReadEventsAsync(
|
|
sourceName: null,
|
|
startUtc: DateTime.UtcNow.AddMinutes(-5),
|
|
endUtc: DateTime.UtcNow,
|
|
maxEvents: 100,
|
|
cancellationToken: TestContext.Current.CancellationToken));
|
|
}
|
|
}
|