using CliFx.Exceptions;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Client.CLI.Commands;
using ZB.MOM.WW.OtOpcUa.Client.CLI.Tests.Fakes;
using ZB.MOM.WW.OtOpcUa.Client.Shared.Models;
namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Tests;
///
/// historyread --aggregate accepts every aggregate the client offers (which is exactly the served set), so the
/// gate recipes in docs/Historian.md that need Range / Delta / PercentGood / ... can run from this CLI.
///
public class HistoryReadAggregateParsingTests
{
/// Every client aggregate, by its name.
/// Each value.
public static TheoryData AllAggregates() => new(Enum.GetValues());
/// Every aggregate name (in any case) reaches the service as that aggregate.
/// The aggregate.
[Theory]
[MemberData(nameof(AllAggregates))]
public async Task Every_aggregate_name_parses(AggregateType aggregate)
{
var fakeService = new FakeOpcUaClientService();
var command = new HistoryReadCommand(new FakeOpcUaClientServiceFactory(fakeService))
{
Url = "opc.tcp://localhost:4840",
NodeId = "ns=2;s=HistNode",
Aggregate = aggregate.ToString().ToUpperInvariant()
};
using var console = TestConsoleHelper.CreateConsole();
await command.ExecuteAsync(console);
fakeService.HistoryReadAggregateCalls.ShouldHaveSingleItem().Aggregate.ShouldBe(aggregate);
}
/// The short aliases still parse.
/// The alias.
/// The aggregate it names.
[Theory]
[InlineData("avg", AggregateType.Average)]
[InlineData("min", AggregateType.Minimum)]
[InlineData("last", AggregateType.End)]
[InlineData("interp", AggregateType.Interpolative)]
[InlineData("mintime", AggregateType.MinimumActualTime)]
[InlineData("maxtime", AggregateType.MaximumActualTime)]
public async Task Aliases_parse(string alias, AggregateType expected)
{
var fakeService = new FakeOpcUaClientService();
var command = new HistoryReadCommand(new FakeOpcUaClientServiceFactory(fakeService))
{
Url = "opc.tcp://localhost:4840",
NodeId = "ns=2;s=HistNode",
Aggregate = alias
};
using var console = TestConsoleHelper.CreateConsole();
await command.ExecuteAsync(console);
fakeService.HistoryReadAggregateCalls.ShouldHaveSingleItem().Aggregate.ShouldBe(expected);
}
///
/// StandardDeviation is no longer offered (no backend serves it): it is refused before connecting, naming the
/// supported set.
///
[Fact]
public async Task StandardDeviation_is_refused_before_connecting()
{
var fakeService = new FakeOpcUaClientService();
var command = new HistoryReadCommand(new FakeOpcUaClientServiceFactory(fakeService))
{
Url = "opc.tcp://localhost:4840",
NodeId = "ns=2;s=HistNode",
Aggregate = "stddev"
};
using var console = TestConsoleHelper.CreateConsole();
var ex = await Should.ThrowAsync(async () => await command.ExecuteAsync(console));
ex.Message.ShouldContain("PercentGood");
fakeService.HistoryReadAggregateCalls.ShouldBeEmpty();
}
}