using Opc.Ua;
using Opc.Ua.Server;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
using HistorianRead = ZB.MOM.WW.OtOpcUa.Core.Abstractions.HistoryReadResult;
namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests;
///
/// #736 — assigning re-syncs
/// HistoryServerCapabilities/MaxReturnDataValues (i=11273) to the source's
/// , read back the way a client would. The Null
/// source (the historian-disabled default) advertises Part 11's "no limit".
///
public sealed class NodeManagerMaxReturnDataValuesSyncTests(BoundsServerFixture fx) : IClassFixture
{
[Fact]
public async Task Setting_the_historian_source_advertises_its_raw_cap()
{
await fx.Gate.WaitAsync(TestContext.Current.CancellationToken);
try
{
fx.Nm.HistorianDataSource = new CappedSource(7_000);
(await ReadAdvertisedAsync()).ShouldBe(7_000u);
fx.Nm.HistorianDataSource = new CappedSource(250);
(await ReadAdvertisedAsync()).ShouldBe(250u);
fx.Nm.HistorianDataSource = null!; // the Null default: no cap
(await ReadAdvertisedAsync()).ShouldBe(0u);
}
finally
{
fx.Nm.HistorianDataSource = null!;
fx.Gate.Release();
}
}
private async Task ReadAdvertisedAsync()
{
var context = new OperationContext(new RequestHeader(), secureChannelContext: null, RequestType.Read, identity: null);
var nodesToRead = new ReadValueIdCollection
{
new ReadValueId { NodeId = VariableIds.HistoryServerCapabilities_MaxReturnDataValues, AttributeId = Attributes.Value },
};
var (values, _) = await fx.Nm.Server.NodeManager.ReadAsync(context, 0, TimestampsToReturn.Neither, nodesToRead, TestContext.Current.CancellationToken);
values.Count.ShouldBe(1);
StatusCode.IsGood(values[0].StatusCode).ShouldBeTrue(values[0].StatusCode.ToString());
return (uint)values[0].Value;
}
private sealed class CappedSource(int cap) : IHistorianDataSource
{
public int MaxRawValuesPerRead => cap;
public Task ReadRawAsync(string r, DateTime s, DateTime e, uint m, CancellationToken ct) =>
NullHistorianDataSource.Instance.ReadRawAsync(r, s, e, m, ct);
public Task ReadProcessedAsync(string r, DateTime s, DateTime e, TimeSpan i, HistoryAggregateType a, CancellationToken ct) =>
NullHistorianDataSource.Instance.ReadProcessedAsync(r, s, e, i, a, ct);
public Task ReadAtTimeAsync(string r, IReadOnlyList t, CancellationToken ct) =>
NullHistorianDataSource.Instance.ReadAtTimeAsync(r, t, ct);
public Task ReadEventsAsync(string? n, DateTime s, DateTime e, int m, CancellationToken ct) =>
NullHistorianDataSource.Instance.ReadEventsAsync(n, s, e, m, ct);
public HistorianHealthSnapshot GetHealthSnapshot() => NullHistorianDataSource.Instance.GetHealthSnapshot();
public void Dispose() { }
}
}