64e3fbe035
v2-ci / build (push) Failing after 1m43s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
Adds <summary>, <param>, <typeparam>, and <inheritdoc/> tags to public members surfaced by commentchecker — resolves 5,847 of 5,869 issues (99.6%) across three /fixdocs passes.
100 lines
4.7 KiB
C#
100 lines
4.7 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
|
|
{
|
|
/// <summary>Verifies MapAggregateToNodeId returns standard Part 13 aggregate for every enum.</summary>
|
|
/// <param name="agg">The history aggregate type to test.</param>
|
|
[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);
|
|
}
|
|
|
|
/// <summary>Verifies MapAggregateToNodeId rejects invalid enum values.</summary>
|
|
[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));
|
|
}
|
|
|
|
/// <summary>Verifies ReadRawAsync throws without initialization.</summary>
|
|
[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));
|
|
}
|
|
|
|
/// <summary>Verifies ReadRawAsync with malformed NodeId returns empty result.</summary>
|
|
[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;
|
|
}
|
|
|
|
/// <summary>Verifies ReadProcessedAsync throws without initialization.</summary>
|
|
[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));
|
|
}
|
|
|
|
/// <summary>Verifies ReadAtTimeAsync throws without initialization.</summary>
|
|
[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));
|
|
}
|
|
|
|
/// <summary>Verifies ReadEventsAsync throws NotSupportedException as documented.</summary>
|
|
[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));
|
|
}
|
|
}
|