test: converge historian and runtime fixtures on SDK 2.0
This commit is contained in:
+3
-3
@@ -114,7 +114,7 @@ public sealed class GatewayBoundingValueTests
|
||||
{
|
||||
var bound = await HistoryBounds.StartBoundAsync(Source(Aveva()), "T", At(-30), reverse: false, 65536, Now, Ct);
|
||||
|
||||
bound!.StatusCode.ShouldBe(Opc.Ua.StatusCodes.BadBoundNotFound);
|
||||
bound!.StatusCode.ShouldBe(Opc.Ua.StatusCodes.BadBoundNotFound.Code);
|
||||
bound.SourceTimestampUtc.ShouldBe(At(-30));
|
||||
bound.Value.ShouldBeNull();
|
||||
}
|
||||
@@ -134,7 +134,7 @@ public sealed class GatewayBoundingValueTests
|
||||
after.Value.ShouldBe(5d);
|
||||
|
||||
var missing = await HistoryBounds.EndBoundAsync(source, "T", HistoryBounds.For(At(0), At(101)), At(100), 65536, Now, Ct);
|
||||
missing.StatusCode.ShouldBe(Opc.Ua.StatusCodes.BadBoundNotFound);
|
||||
missing.StatusCode.ShouldBe(Opc.Ua.StatusCodes.BadBoundNotFound.Code);
|
||||
missing.SourceTimestampUtc.ShouldBe(At(101));
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ public sealed class GatewayBoundingValueTests
|
||||
var calls = fake.ReadRawCallCount;
|
||||
var beyond = Now.AddDays(3);
|
||||
var missing = await HistoryBounds.EndBoundAsync(source, "T", HistoryBounds.For(At(0), beyond), At(100), 65536, Now, Ct);
|
||||
missing.StatusCode.ShouldBe(Opc.Ua.StatusCodes.BadBoundNotFound);
|
||||
missing.StatusCode.ShouldBe(Opc.Ua.StatusCodes.BadBoundNotFound.Code);
|
||||
missing.SourceTimestampUtc.ShouldBe(beyond);
|
||||
fake.ReadRawCallCount.ShouldBe(calls, "a bound beyond the horizon is not found without a read");
|
||||
source.GetHealthSnapshot().TotalFailures.ShouldBe(0);
|
||||
|
||||
+22
-19
@@ -106,7 +106,7 @@ public sealed class GatewayCeilingPagingTests : IDisposable
|
||||
try
|
||||
{
|
||||
var first = ReadRaw(nm, nodeId, At(0), At(3600), 5000, null);
|
||||
first.Error.StatusCode.Code.ShouldBe(StatusCodes.Good);
|
||||
first.Error.StatusCode.ShouldBe(StatusCodes.Good);
|
||||
first.Values.Count.ShouldBe(FirstPage);
|
||||
first.Cp.ShouldNotBeNull();
|
||||
// The budget the client asked for (+ lookahead + allowance, refused naming 1000), the ceiling re-read that cannot
|
||||
@@ -114,7 +114,7 @@ public sealed class GatewayCeilingPagingTests : IDisposable
|
||||
fake.RawCalls.Select(c => c.MaxValues).ShouldBe([5000 + 1 + RawAggregateReader.PreWindowAllowance, Ceiling, Ceiling]);
|
||||
|
||||
var (rest, _, status) = DrainFrom(nm, nodeId, At(0), At(3600), 5000, first.Cp);
|
||||
status.Code.ShouldBe(StatusCodes.Good);
|
||||
status.ShouldBe(StatusCodes.Good);
|
||||
first.Values.Concat(rest).ShouldBe(PerSecond(3600).Select(s => s.Item2));
|
||||
Refusals(fake).ShouldBe(1);
|
||||
}
|
||||
@@ -140,7 +140,7 @@ public sealed class GatewayCeilingPagingTests : IDisposable
|
||||
? DrainFrom(nm, nodeId, At(3600), At(-1), n, null)
|
||||
: DrainFrom(nm, nodeId, At(0), At(3600), n, null);
|
||||
|
||||
status.Code.ShouldBe(StatusCodes.Good);
|
||||
status.ShouldBe(StatusCodes.Good);
|
||||
var expected = stored.Select(s => s.Item2);
|
||||
values.ShouldBe(reverse ? expected.Reverse() : expected);
|
||||
pages[0].ShouldBe(FirstPage);
|
||||
@@ -217,10 +217,10 @@ public sealed class GatewayCeilingPagingTests : IDisposable
|
||||
|
||||
var (values, pages, status) = DrainFrom(nm, nodeId, At(0), At(5000), n, null, maxPages: 60);
|
||||
var expected = stored.Select(s => s.Item2).ToList();
|
||||
if (status.Code == StatusCodes.Good) values.ShouldBe(expected);
|
||||
if (status == StatusCodes.Good) values.ShouldBe(expected);
|
||||
else
|
||||
{
|
||||
status.Code.ShouldBe(StatusCodes.BadTooManyOperations);
|
||||
status.ShouldBe(StatusCodes.BadTooManyOperations);
|
||||
values.ShouldBe(expected.Take(values.Count)); // an exact prefix
|
||||
size.ShouldBeGreaterThan(L - 2, "a cluster that fits the over-fetch is always served");
|
||||
}
|
||||
@@ -254,7 +254,7 @@ public sealed class GatewayCeilingPagingTests : IDisposable
|
||||
ds.MaxRawValuesPerRead.ShouldBe(0);
|
||||
|
||||
var (rest, pages, status) = DrainFrom(nm, nodeId, At(0), At(5000), 0, first.Cp, maxPages: 20);
|
||||
status.Code.ShouldBe(StatusCodes.Good);
|
||||
status.ShouldBe(StatusCodes.Good);
|
||||
first.Values.Concat(rest).ShouldBe(stored.Select(s => s.Item2));
|
||||
pages.Count.ShouldBeLessThan(20);
|
||||
}
|
||||
@@ -278,7 +278,7 @@ public sealed class GatewayCeilingPagingTests : IDisposable
|
||||
fake.MaxValuesCeiling = 500; // the operator lowered it
|
||||
fake.RawCalls.Clear();
|
||||
var (rest, pages, status) = DrainFrom(nm, nodeId, At(0), At(3600), 5000, p2.Cp, maxPages: 20);
|
||||
status.Code.ShouldBe(StatusCodes.Good);
|
||||
status.ShouldBe(StatusCodes.Good);
|
||||
got.AddRange(rest);
|
||||
got.ShouldBe(stored.Select(s => s.Item2));
|
||||
pages.ShouldAllBe(p => p <= 500 - RawAggregateReader.PreWindowAllowance);
|
||||
@@ -302,7 +302,7 @@ public sealed class GatewayCeilingPagingTests : IDisposable
|
||||
var start = At(10).AddMilliseconds(500);
|
||||
var end = At(3000).AddMilliseconds(500);
|
||||
var (values, pages, status) = DrainFrom(nm, nodeId, start, end, 5000, null, returnBounds: true);
|
||||
status.Code.ShouldBe(StatusCodes.Good);
|
||||
status.ShouldBe(StatusCodes.Good);
|
||||
values.ShouldBe(Enumerable.Range(10, 2992).Select(i => (double)i));
|
||||
pages.ShouldAllBe(p => p <= L);
|
||||
Refusals(fake).ShouldBe(0);
|
||||
@@ -325,7 +325,7 @@ public sealed class GatewayCeilingPagingTests : IDisposable
|
||||
try
|
||||
{
|
||||
var r = ReadRaw(nm, nodeId, DateTime.MinValue, T0.AddMilliseconds(200_000), n, null);
|
||||
r.Error.StatusCode.Code.ShouldBe(StatusCodes.Good);
|
||||
r.Error.StatusCode.ShouldBe(StatusCodes.Good);
|
||||
r.Cp.ShouldNotBeNull();
|
||||
var page = ceiling - RawAggregateReader.PreWindowAllowance - 1;
|
||||
r.Values.ShouldBe(Enumerable.Range(200_000 - r.Values.Count, r.Values.Count).Reverse().Select(i => (double)i));
|
||||
@@ -360,7 +360,7 @@ public sealed class GatewayCeilingPagingTests : IDisposable
|
||||
try
|
||||
{
|
||||
var (values, pages, status) = DrainFrom(nm, nodeId, DateTime.UnixEpoch, DateTime.UnixEpoch.AddDays(1), 0, null);
|
||||
status.Code.ShouldBe(StatusCodes.Good);
|
||||
status.ShouldBe(StatusCodes.Good);
|
||||
values.ShouldBe(stored.Select(s => s.Item2));
|
||||
pages.Count.ShouldBeGreaterThan(1);
|
||||
}
|
||||
@@ -377,7 +377,7 @@ public sealed class GatewayCeilingPagingTests : IDisposable
|
||||
{
|
||||
ReadRaw(nm, nodeId, DateTime.UnixEpoch, DateTime.UnixEpoch.AddSeconds(5), 5000, null); // learns the ceiling
|
||||
var r = ReadRaw(nm, nodeId, DateTime.MinValue, DateTime.UnixEpoch.AddDays(30), 10, null);
|
||||
r.Error.StatusCode.Code.ShouldBe(StatusCodes.Good);
|
||||
r.Error.StatusCode.ShouldBe(StatusCodes.Good);
|
||||
r.Values.ShouldBe(Enumerable.Range(2991, 10).Reverse().Select(i => (double)i)); // the LATEST ten, newest first
|
||||
}
|
||||
finally { await host.DisposeAsync(); }
|
||||
@@ -425,7 +425,7 @@ public sealed class GatewayCeilingPagingTests : IDisposable
|
||||
fake.RawCalls.Clear();
|
||||
|
||||
var (values, _, status) = DrainFrom(nm, nodeId, At(0), x.AddDays(1), n, null);
|
||||
status.Code.ShouldBe(StatusCodes.Good);
|
||||
status.ShouldBe(StatusCodes.Good);
|
||||
values.ShouldBe(stored.Select(s => s.Item2));
|
||||
Refusals(fake).ShouldBe(0);
|
||||
EveryRequestFits(fake);
|
||||
@@ -476,7 +476,7 @@ public sealed class GatewayCeilingPagingTests : IDisposable
|
||||
try
|
||||
{
|
||||
var r = ReadRaw(nm, nodeId, At(0), At(10), 10, null);
|
||||
r.Error.StatusCode.Code.ShouldBe(StatusCodes.BadNoCommunication);
|
||||
r.Error.StatusCode.ShouldBe(StatusCodes.BadNoCommunication);
|
||||
}
|
||||
finally { await host.DisposeAsync(); }
|
||||
}
|
||||
@@ -528,7 +528,7 @@ public sealed class GatewayCeilingPagingTests : IDisposable
|
||||
private static (IReadOnlyList<double> Values, ServiceResult Error, byte[]? Cp) ReadRaw(
|
||||
OtOpcUaNodeManager nm, NodeId nodeId, DateTime start, DateTime end, uint max, byte[]? inboundCp, bool returnBounds = false)
|
||||
{
|
||||
var context = new OperationContext(new RequestHeader(), secureChannelContext: null, RequestType.HistoryRead, identity: null);
|
||||
var context = new OperationContext(new RequestHeader(), secureChannelContext: null, RequestType.HistoryRead, requestLifetime: RequestLifetime.None, identity: null);
|
||||
var details = new ReadRawModifiedDetails
|
||||
{
|
||||
ReturnBounds = returnBounds,
|
||||
@@ -537,16 +537,19 @@ public sealed class GatewayCeilingPagingTests : IDisposable
|
||||
EndTime = end,
|
||||
NumValuesPerNode = max,
|
||||
};
|
||||
var nodesToRead = new List<HistoryReadValueId> { new() { NodeId = nodeId, ContinuationPoint = inboundCp } };
|
||||
var nodesToRead = new List<HistoryReadValueId> { new() { NodeId = nodeId, ContinuationPoint = inboundCp is null ? default : ByteString.From(inboundCp) } };
|
||||
var results = new List<SdkHistoryReadResult> { null! };
|
||||
var errors = new List<ServiceResult> { null! };
|
||||
nm.HistoryRead(context, details, TimestampsToReturn.Both, releaseContinuationPoints: false, nodesToRead, results, errors);
|
||||
|
||||
var values = new List<double>();
|
||||
if (results[0]?.HistoryData is { } ho && !ExtensionObject.IsNull(ho))
|
||||
foreach (var dv in ((HistoryData)ExtensionObject.ToEncodeable(ho)).DataValues)
|
||||
values.Add(Convert.ToDouble(dv.Value));
|
||||
return (values, errors[0], results[0]?.ContinuationPoint);
|
||||
if (results[0]?.HistoryData is { IsNull: false } historyData)
|
||||
{
|
||||
var data = (HistoryData)ExtensionObject.ToEncodeable(historyData)!;
|
||||
foreach (var dv in data.DataValues)
|
||||
values.Add(Convert.ToDouble(SdkValueBoundary.ToClr(dv.WrappedValue)));
|
||||
}
|
||||
return (values, errors[0], results[0]?.ContinuationPoint is { IsNull: false } cp ? cp.ToArray() : null);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
+11
-8
@@ -205,7 +205,7 @@ public sealed class GatewayRawCapTests : IDisposable
|
||||
? DrainFrom(nm, nodeId, At(3600), At(-1), n, null)
|
||||
: DrainFrom(nm, nodeId, At(0), At(3600), n, null);
|
||||
|
||||
status.Code.ShouldBe(StatusCodes.Good);
|
||||
status.ShouldBe(StatusCodes.Good);
|
||||
var expected = Enumerable.Range(0, 3600).Select(i => (double)i);
|
||||
values.ShouldBe(reverse ? expected.Reverse() : expected);
|
||||
pages.Count.ShouldBeGreaterThan(1, "a year-sized window at N = 0 is paged, not one shot");
|
||||
@@ -224,7 +224,7 @@ public sealed class GatewayRawCapTests : IDisposable
|
||||
try
|
||||
{
|
||||
var (values, pages, status) = DrainFrom(nm, nodeId, At(10).AddMilliseconds(500), At(3000).AddMilliseconds(500), 0, null, returnBounds: true);
|
||||
status.Code.ShouldBe(StatusCodes.Good);
|
||||
status.ShouldBe(StatusCodes.Good);
|
||||
values.ShouldBe(Enumerable.Range(10, 2992).Select(i => (double)i)); // start bound +10, data +11..+3000, end bound +3001
|
||||
pages.ShouldAllBe(p => p <= Cap);
|
||||
fake.RawCalls.ShouldAllBe(c => c.MaxValues > 0 && c.MaxValues <= Cap + RawAggregateReader.PreWindowAllowance);
|
||||
@@ -277,21 +277,24 @@ public sealed class GatewayRawCapTests : IDisposable
|
||||
private static (IReadOnlyList<double> Values, ServiceResult Error, byte[]? Cp) ReadRaw(
|
||||
OtOpcUaNodeManager nm, NodeId nodeId, DateTime start, DateTime end, uint max, byte[]? inboundCp, bool returnBounds = false)
|
||||
{
|
||||
var context = new OperationContext(new RequestHeader(), secureChannelContext: null, RequestType.HistoryRead, identity: null);
|
||||
var context = new OperationContext(new RequestHeader(), secureChannelContext: null, RequestType.HistoryRead, requestLifetime: RequestLifetime.None, identity: null);
|
||||
var details = new ReadRawModifiedDetails
|
||||
{
|
||||
ReturnBounds = returnBounds, IsReadModified = false, StartTime = start, EndTime = end, NumValuesPerNode = max,
|
||||
};
|
||||
var nodesToRead = new List<HistoryReadValueId> { new() { NodeId = nodeId, ContinuationPoint = inboundCp } };
|
||||
var nodesToRead = new List<HistoryReadValueId> { new() { NodeId = nodeId, ContinuationPoint = inboundCp is null ? default : ByteString.From(inboundCp) } };
|
||||
var results = new List<SdkHistoryReadResult> { null! };
|
||||
var errors = new List<ServiceResult> { null! };
|
||||
nm.HistoryRead(context, details, TimestampsToReturn.Both, releaseContinuationPoints: false, nodesToRead, results, errors);
|
||||
|
||||
var values = new List<double>();
|
||||
if (results[0]?.HistoryData is { } ho && !ExtensionObject.IsNull(ho))
|
||||
foreach (var dv in ((HistoryData)ExtensionObject.ToEncodeable(ho)).DataValues)
|
||||
values.Add(Convert.ToDouble(dv.Value));
|
||||
return (values, errors[0], results[0]?.ContinuationPoint);
|
||||
if (results[0]?.HistoryData is { IsNull: false } historyData)
|
||||
{
|
||||
var data = (HistoryData)ExtensionObject.ToEncodeable(historyData)!;
|
||||
foreach (var dv in data.DataValues)
|
||||
values.Add(Convert.ToDouble(SdkValueBoundary.ToClr(dv.WrappedValue)));
|
||||
}
|
||||
return (values, errors[0], results[0]?.ContinuationPoint is { IsNull: false } cp ? cp.ToArray() : null);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
+2
-3
@@ -28,7 +28,6 @@ using LocalizedText = Opc.Ua.LocalizedText;
|
||||
using Proto = ZB.MOM.WW.MxGateway.Contracts.Proto;
|
||||
using UaNodeId = Opc.Ua.NodeId;
|
||||
using Variant = Opc.Ua.Variant;
|
||||
using VariantCollection = Opc.Ua.VariantCollection;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Runtime.Tests.Drivers;
|
||||
|
||||
@@ -505,9 +504,9 @@ public sealed class NativeAlarmRestatementEndToEndTests : RuntimeActorTestBase
|
||||
}
|
||||
|
||||
/// <summary>An upstream A&C condition event, in the driver's select-clause order.</summary>
|
||||
private static VariantCollection ConditionFields(bool active, bool acked) =>
|
||||
private static Variant[] ConditionFields(bool active, bool acked) =>
|
||||
[
|
||||
new Variant(new byte[] { 1 }), // EventId
|
||||
new Variant(Opc.Ua.ByteString.From(new byte[] { 1 })), // EventId
|
||||
new Variant(new UaNodeId("TripAlarmType", 3)), // EventType
|
||||
new Variant(UaNodeId.Parse(UpstreamSource)), // SourceNode
|
||||
new Variant(new LocalizedText("tripped")), // Message
|
||||
|
||||
@@ -35,7 +35,7 @@ public sealed class ServiceLevelEndToEndTests : RuntimeActorTestBase
|
||||
port => new OpcUaApplicationHost(
|
||||
BuildOptions("PrimaryLeader", pkiRoot, port),
|
||||
NullLogger<OpcUaApplicationHost>.Instance),
|
||||
() => new StandardServer(), Ct);
|
||||
() => new StandardServer(Opc.Ua.DefaultTelemetry.Create(_ => { })), Ct);
|
||||
await using var host = started.Host;
|
||||
var server = started.Server;
|
||||
|
||||
@@ -58,7 +58,7 @@ public sealed class ServiceLevelEndToEndTests : RuntimeActorTestBase
|
||||
CorrelationId: CorrelationId.NewId()));
|
||||
|
||||
AwaitAssertion(() =>
|
||||
server.CurrentInstance.ServerObject.ServiceLevel.Value.ShouldBe((byte)240));
|
||||
server.CurrentInstance.ServerObject.ServiceLevel.ShouldNotBeNull().Value.ShouldBe((byte)240));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -77,7 +77,7 @@ public sealed class ServiceLevelEndToEndTests : RuntimeActorTestBase
|
||||
port => new OpcUaApplicationHost(
|
||||
BuildOptions("Secondary", pkiRoot, port),
|
||||
NullLogger<OpcUaApplicationHost>.Instance),
|
||||
() => new StandardServer(), Ct);
|
||||
() => new StandardServer(Opc.Ua.DefaultTelemetry.Create(_ => { })), Ct);
|
||||
await using var host = started.Host;
|
||||
var server = started.Server;
|
||||
|
||||
@@ -100,7 +100,7 @@ public sealed class ServiceLevelEndToEndTests : RuntimeActorTestBase
|
||||
CorrelationId: CorrelationId.NewId()));
|
||||
|
||||
AwaitAssertion(() =>
|
||||
server.CurrentInstance.ServerObject.ServiceLevel.Value.ShouldBe((byte)100));
|
||||
server.CurrentInstance.ServerObject.ServiceLevel.ShouldNotBeNull().Value.ShouldBe((byte)100));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user