Replace direct SQL queries against Historian Runtime database with the Wonderware Historian managed SDK (ArchestrA.HistorianAccess). Add HistoryServerCapabilities node, AggregateFunctions folder, continuation points, ReadAtTime interpolation, ReturnBounds, ReadModified rejection, HistoricalDataConfiguration per node, historical event access, and client-side StandardDeviation aggregate support. Remove screenshot tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
160 lines
4.7 KiB
C#
160 lines
4.7 KiB
C#
using Opc.Ua;
|
|
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.LmxOpcUa.Client.Shared.Models;
|
|
using ZB.MOM.WW.LmxOpcUa.Client.UI.Services;
|
|
using ZB.MOM.WW.LmxOpcUa.Client.UI.Tests.Fakes;
|
|
using ZB.MOM.WW.LmxOpcUa.Client.UI.ViewModels;
|
|
|
|
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Tests;
|
|
|
|
public class HistoryViewModelTests
|
|
{
|
|
private readonly FakeOpcUaClientService _service;
|
|
private readonly HistoryViewModel _vm;
|
|
|
|
public HistoryViewModelTests()
|
|
{
|
|
_service = new FakeOpcUaClientService
|
|
{
|
|
HistoryRawResult =
|
|
[
|
|
new DataValue(new Variant(10), StatusCodes.Good, DateTime.UtcNow, DateTime.UtcNow),
|
|
new DataValue(new Variant(20), StatusCodes.Good, DateTime.UtcNow, DateTime.UtcNow)
|
|
],
|
|
HistoryAggregateResult =
|
|
[
|
|
new DataValue(new Variant(15.0), StatusCodes.Good, DateTime.UtcNow, DateTime.UtcNow)
|
|
]
|
|
};
|
|
var dispatcher = new SynchronousUiDispatcher();
|
|
_vm = new HistoryViewModel(_service, dispatcher);
|
|
}
|
|
|
|
[Fact]
|
|
public void ReadHistoryCommand_CannotExecute_WhenDisconnected()
|
|
{
|
|
_vm.IsConnected = false;
|
|
_vm.SelectedNodeId = "ns=2;s=SomeNode";
|
|
_vm.ReadHistoryCommand.CanExecute(null).ShouldBeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public void ReadHistoryCommand_CannotExecute_WhenNoNodeSelected()
|
|
{
|
|
_vm.IsConnected = true;
|
|
_vm.SelectedNodeId = null;
|
|
_vm.ReadHistoryCommand.CanExecute(null).ShouldBeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public void ReadHistoryCommand_CanExecute_WhenConnectedAndNodeSelected()
|
|
{
|
|
_vm.IsConnected = true;
|
|
_vm.SelectedNodeId = "ns=2;s=SomeNode";
|
|
_vm.ReadHistoryCommand.CanExecute(null).ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReadHistoryCommand_Raw_PopulatesResults()
|
|
{
|
|
_vm.IsConnected = true;
|
|
_vm.SelectedNodeId = "ns=2;s=SomeNode";
|
|
_vm.SelectedAggregateType = null; // Raw
|
|
|
|
await _vm.ReadHistoryCommand.ExecuteAsync(null);
|
|
|
|
_vm.Results.Count.ShouldBe(2);
|
|
_vm.Results[0].Value.ShouldBe("10");
|
|
_vm.Results[1].Value.ShouldBe("20");
|
|
_service.HistoryReadRawCallCount.ShouldBe(1);
|
|
_service.HistoryReadAggregateCallCount.ShouldBe(0);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReadHistoryCommand_Aggregate_PopulatesResults()
|
|
{
|
|
_vm.IsConnected = true;
|
|
_vm.SelectedNodeId = "ns=2;s=SomeNode";
|
|
_vm.SelectedAggregateType = AggregateType.Average;
|
|
|
|
await _vm.ReadHistoryCommand.ExecuteAsync(null);
|
|
|
|
_vm.Results.Count.ShouldBe(1);
|
|
_vm.Results[0].Value.ShouldBe("15");
|
|
_service.HistoryReadAggregateCallCount.ShouldBe(1);
|
|
_service.LastAggregateType.ShouldBe(AggregateType.Average);
|
|
_service.HistoryReadRawCallCount.ShouldBe(0);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReadHistoryCommand_ClearsResultsBefore()
|
|
{
|
|
_vm.Results.Add(new HistoryValueViewModel("old", "Good", "t1", "t2"));
|
|
_vm.IsConnected = true;
|
|
_vm.SelectedNodeId = "ns=2;s=SomeNode";
|
|
|
|
await _vm.ReadHistoryCommand.ExecuteAsync(null);
|
|
|
|
_vm.Results.ShouldNotContain(r => r.Value == "old");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReadHistoryCommand_IsLoading_FalseAfterComplete()
|
|
{
|
|
_vm.IsConnected = true;
|
|
_vm.SelectedNodeId = "ns=2;s=SomeNode";
|
|
|
|
await _vm.ReadHistoryCommand.ExecuteAsync(null);
|
|
|
|
_vm.IsLoading.ShouldBeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public void DefaultValues_AreCorrect()
|
|
{
|
|
_vm.MaxValues.ShouldBe(1000);
|
|
_vm.IntervalMs.ShouldBe(3600000);
|
|
_vm.SelectedAggregateType.ShouldBeNull();
|
|
_vm.IsAggregateRead.ShouldBeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public void IsAggregateRead_TrueWhenAggregateSelected()
|
|
{
|
|
_vm.SelectedAggregateType = AggregateType.Maximum;
|
|
_vm.IsAggregateRead.ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void AggregateTypes_ContainsNullForRaw()
|
|
{
|
|
_vm.AggregateTypes.ShouldContain((AggregateType?)null);
|
|
_vm.AggregateTypes.Count.ShouldBe(8); // null + 7 enum values
|
|
}
|
|
|
|
[Fact]
|
|
public void Clear_ResetsState()
|
|
{
|
|
_vm.SelectedNodeId = "ns=2;s=SomeNode";
|
|
_vm.Results.Add(new HistoryValueViewModel("v", "s", "t1", "t2"));
|
|
|
|
_vm.Clear();
|
|
|
|
_vm.Results.ShouldBeEmpty();
|
|
_vm.SelectedNodeId.ShouldBeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReadHistoryCommand_Error_ShowsErrorInResults()
|
|
{
|
|
_service.HistoryException = new Exception("History not supported");
|
|
_vm.IsConnected = true;
|
|
_vm.SelectedNodeId = "ns=2;s=SomeNode";
|
|
|
|
await _vm.ReadHistoryCommand.ExecuteAsync(null);
|
|
|
|
_vm.Results.Count.ShouldBe(1);
|
|
_vm.Results[0].Value.ShouldContain("History not supported");
|
|
}
|
|
} |