Files
lmxopcua/tests/Client/ZB.MOM.WW.OtOpcUa.Client.Shared.Tests/Helpers/HistoryReadStatusTests.cs
T
Joseph Doherty f7f7d948cd fix(client): surface a Bad per-node HistoryRead status instead of '0 values returned'
DefaultSessionAdapter swallowed a Bad HistoryReadResult.StatusCode (raw: break;
aggregate: skip) so Client.CLI/UI printed an empty result for
BadHistoryOperationUnsupported / BadUserAccessDenied. It now throws a
ServiceResultException naming the node and status; BadNoData stays empty.

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
2026-10-08 23:35:13 -04:00

39 lines
1.5 KiB
C#

using Opc.Ua;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Client.Shared.Helpers;
namespace ZB.MOM.WW.OtOpcUa.Client.Shared.Tests.Helpers;
public class HistoryReadStatusTests
{
/// <summary>A refused read must surface, carrying the status code, rather than read as an empty result.</summary>
/// <param name="code">The Bad per-node status code.</param>
[Theory]
[InlineData(StatusCodes.BadHistoryOperationUnsupported)]
[InlineData(StatusCodes.BadUserAccessDenied)]
[InlineData(StatusCodes.BadNodeIdUnknown)]
[InlineData(StatusCodes.BadTimeout)]
public void Bad_status_throws_ServiceResultException_with_the_code(uint code)
{
var ex = Should.Throw<ServiceResultException>(
() => HistoryReadStatus.ThrowIfRefused(new StatusCode(code), new NodeId("n", 2)));
ex.StatusCode.ShouldBe(code);
ex.Message.ShouldContain("ns=2;s=n");
}
/// <summary>Good, GoodNoData, Uncertain and BadNoData are all non-refusals (the window may simply be empty).</summary>
/// <param name="code">The non-refusal status code.</param>
[Theory]
[InlineData(StatusCodes.Good)]
[InlineData(StatusCodes.GoodNoData)]
[InlineData(StatusCodes.GoodMoreData)]
[InlineData(StatusCodes.UncertainNoCommunicationLastUsableValue)]
[InlineData(StatusCodes.BadNoData)]
public void Non_refusal_status_does_not_throw(uint code)
{
Should.NotThrow(() => HistoryReadStatus.ThrowIfRefused(new StatusCode(code), new NodeId("n", 2)));
}
}