--- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/AvevaGatewayHistoryLiveGateTests.cs +++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/AvevaGatewayHistoryLiveGateTests.cs @@ -15,7 +15,7 @@ namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests; /// -/// Gitea #801 (SDK 2 live gate, "real AVEVA history"): the booted OtOpcUa server, with the production +/// Gitea #801 BASELINE PORT (SDK 1.5.378.182, master efb9197a) (SDK 2 live gate, "real AVEVA history"): the booted OtOpcUa server, with the production /// Gateway backend ( → GatewayHistorianDataSource) pointed at a REAL /// HistorianGateway in front of the real AVEVA Historian, serves HistoryRead over a real SDK client session. /// Every wire answer is compared with the same backend's direct answer @@ -283,11 +283,11 @@ { var t = DateTime.UtcNow.AddHours(-1); var insert = new UpdateDataDetails { NodeId = Node(sandboxNode), PerformInsertReplace = PerformUpdateType.Insert }; - insert.UpdateValues += new DataValue(Variant.From(801.0), StatusCodes.Good, t, t); + insert.UpdateValues.Add(new DataValue(new Variant(801.0), StatusCodes.Good, t, t)); var del = new DeleteRawModifiedDetails { NodeId = Node(sandboxNode), IsDeleteModified = false, StartTime = t, EndTime = t.AddSeconds(1) }; foreach (var (name, details) in new (string, IEncodeable)[] { ("insert", insert), ("deleteRaw", del) }) { - var response = await session.HistoryUpdateAsync(null, new ExtensionObject[] { new(details) }, ct); + var response = await session.HistoryUpdateAsync(null, new ExtensionObjectCollection { new ExtensionObject(details) }, ct); var result = response.Results.ToList().ShouldHaveSingleItem(); var status = Name(result.StatusCode); report.Add(new Case($"historyUpdate.{name}", sandboxTag, null, "wire", status, @@ -316,7 +316,7 @@ { StartTime = start, EndTime = end, NumValuesPerNode = max, IsReadModified = false, ReturnBounds = returnBounds, }; - var (status, rows, cp) = await HistoryReadAsync(session, details, node, default, ct); + var (status, rows, cp) = await HistoryReadAsync(session, details, node, null, ct); await ReleaseAsync(session, details, node, cp, ct); return new WireRead(status, rows, 1); } @@ -330,7 +330,7 @@ }; var all = new List(); var pages = 0; - ByteString cp = default; + byte[]? cp = null; string status; do { @@ -339,14 +339,14 @@ pages++; if (status.StartsWith("Bad", StringComparison.Ordinal)) break; } - while (!cp.IsEmpty && pages < 10_000); + while (cp is { Length: > 0 } && pages < 10_000); return new WireRead(status, all, pages); } private static async Task ReadModifiedAsync(ISession session, NodeId node, DateTime start, DateTime end, CancellationToken ct) { var details = new ReadRawModifiedDetails { StartTime = start, EndTime = end, NumValuesPerNode = 0, IsReadModified = true, ReturnBounds = false }; - var (status, _, cp) = await HistoryReadAsync(session, details, node, default, ct); + var (status, _, cp) = await HistoryReadAsync(session, details, node, null, ct); await ReleaseAsync(session, details, node, cp, ct); return status; } @@ -357,12 +357,12 @@ var details = new ReadProcessedDetails { StartTime = start, EndTime = end, ProcessingInterval = IntervalMs, - AggregateType = new List { aggregate }, + AggregateType = new NodeIdCollection { aggregate }, AggregateConfiguration = new AggregateConfiguration { UseServerCapabilitiesDefaults = true }, }; var all = new List(); var pages = 0; - ByteString cp = default; + byte[]? cp = null; string status; do { @@ -371,36 +371,36 @@ pages++; if (status.StartsWith("Bad", StringComparison.Ordinal)) break; } - while (!cp.IsEmpty && pages < 1000); + while (cp is { Length: > 0 } && pages < 1000); return new WireRead(status, all, pages); } private static async Task ReadAtTimeAsync(ISession session, NodeId node, IReadOnlyList times, CancellationToken ct) { - var details = new ReadAtTimeDetails { ReqTimes = times.Select(t => (DateTimeUtc)t).ToList(), UseSimpleBounds = true }; - var (status, rows, cp) = await HistoryReadAsync(session, details, node, default, ct); + var details = new ReadAtTimeDetails { ReqTimes = new DateTimeCollection(times), UseSimpleBounds = true }; + var (status, rows, cp) = await HistoryReadAsync(session, details, node, null, ct); await ReleaseAsync(session, details, node, cp, ct); return new WireRead(status, rows, 1); } - private static async Task<(string Status, List Rows, ByteString Cp)> HistoryReadAsync( - ISession session, IEncodeable details, NodeId node, ByteString cp, CancellationToken ct) + private static async Task<(string Status, List Rows, byte[]? Cp)> HistoryReadAsync( + ISession session, IEncodeable details, NodeId node, byte[]? cp, CancellationToken ct) { var response = await session.HistoryReadAsync(null, new ExtensionObject(details), TimestampsToReturn.Both, false, - new HistoryReadValueId[] { new() { NodeId = node, ContinuationPoint = cp } }, ct); + new HistoryReadValueIdCollection { new HistoryReadValueId { NodeId = node, ContinuationPoint = cp } }, ct); var result = response.Results.ToList().ShouldHaveSingleItem(); var rows = new List(); - if (!result.HistoryData.IsNull && ExtensionObject.ToEncodeable(result.HistoryData) is HistoryData data) + if (result.HistoryData?.Body is HistoryData data) rows.AddRange(data.DataValues.ToList().Select(dv => new Row( - Fmt(dv.ClrValue()), dv.StatusCode.Code, Ts(dv.SourceTimestamp), Ts(dv.ServerTimestamp)))); + Fmt(dv.Value), dv.StatusCode.Code, Ts(dv.SourceTimestamp), Ts(dv.ServerTimestamp)))); return (Name(result.StatusCode), rows, result.ContinuationPoint); } - private static async Task ReleaseAsync(ISession session, IEncodeable details, NodeId node, ByteString cp, CancellationToken ct) + private static async Task ReleaseAsync(ISession session, IEncodeable details, NodeId node, byte[]? cp, CancellationToken ct) { - if (cp.IsEmpty) return; + if (cp is not { Length: > 0 }) return; await session.HistoryReadAsync(null, new ExtensionObject(details), TimestampsToReturn.Both, true, - new HistoryReadValueId[] { new() { NodeId = node, ContinuationPoint = cp } }, ct); + new HistoryReadValueIdCollection { new HistoryReadValueId { NodeId = node, ContinuationPoint = cp } }, ct); } private static async Task ReadEventsAsync(ISession session, NodeId node, DateTime start, DateTime end, uint page, @@ -408,33 +408,33 @@ { var filter = new EventFilter(); foreach (var field in new[] { "EventId", "Time", "ReceiveTime", "SourceName", "Message", "Severity" }) - filter.SelectClauses += new SimpleAttributeOperand(ObjectTypeIds.BaseEventType, new QualifiedName(field)) { AttributeId = Attributes.Value }; + filter.SelectClauses.Add(new SimpleAttributeOperand(ObjectTypeIds.BaseEventType, new QualifiedName(field)) { AttributeId = Attributes.Value }); var details = new ReadEventDetails { StartTime = start, EndTime = end, NumValuesPerNode = page, Filter = filter }; var rows = new List(); var pages = 0; - ByteString cp = default; + byte[]? cp = null; string status; do { var response = await session.HistoryReadAsync(null, new ExtensionObject(details), TimestampsToReturn.Both, false, - new HistoryReadValueId[] { new() { NodeId = node, ContinuationPoint = cp } }, ct); + new HistoryReadValueIdCollection { new HistoryReadValueId { NodeId = node, ContinuationPoint = cp } }, ct); var result = response.Results.ToList().ShouldHaveSingleItem(); status = Name(result.StatusCode); cp = result.ContinuationPoint; pages++; - if (!result.HistoryData.IsNull && ExtensionObject.ToEncodeable(result.HistoryData) is HistoryEvent he) + if (result.HistoryData?.Body is HistoryEvent he) foreach (var e in he.Events.ToList()) { var f = e.EventFields.ToList(); rows.Add(new EventRow( - f[0].ClrValue() is byte[] id ? System.Text.Encoding.UTF8.GetString(id) : Fmt(f[0].ClrValue()), - f[1].ClrValue() as DateTime? ?? default, f[2].ClrValue() as DateTime? ?? default, - f[3].ClrValue() as string, f[4].ClrValue() is LocalizedText lt ? lt.Text : Fmt(f[4].ClrValue()), - Convert.ToUInt16(f[5].ClrValue() ?? 0, CultureInfo.InvariantCulture))); + f[0].Value is byte[] id ? System.Text.Encoding.UTF8.GetString(id) : Fmt(f[0].Value), + f[1].Value as DateTime? ?? default, f[2].Value as DateTime? ?? default, + f[3].Value as string, f[4].Value is LocalizedText lt ? lt.Text : Fmt(f[4].Value), + Convert.ToUInt16(f[5].Value ?? 0, CultureInfo.InvariantCulture))); } if (status.StartsWith("Bad", StringComparison.Ordinal)) break; } - while (!cp.IsEmpty && pages < 10_000); + while (cp is { Length: > 0 } && pages < 10_000); return new EventRead(status, rows, pages); } @@ -446,9 +446,9 @@ ("UserAccessLevel", Attributes.UserAccessLevel), ("DataType", Attributes.DataType), }; var response = await session.ReadAsync(null, 0, TimestampsToReturn.Neither, - ids.Select(a => new ReadValueId { NodeId = node, AttributeId = a.Id }).ToArray(), ct); + new ReadValueIdCollection(ids.Select(a => new ReadValueId { NodeId = node, AttributeId = a.Id })), ct); var results = response.Results.ToList(); - return ids.Select((a, i) => (a.Name, Value: Fmt(results[i].ClrValue()))) + return ids.Select((a, i) => (a.Name, Value: Fmt(results[i].Value))) .ToDictionary(x => x.Name, x => x.Value); } @@ -460,9 +460,9 @@ if (vars.Count > 0) { var response = await session.ReadAsync(null, 0, TimestampsToReturn.Neither, - vars.Select(r => new ReadValueId { NodeId = ExpandedNodeId.ToNodeId(r.NodeId, session.NamespaceUris), AttributeId = Attributes.Value }).ToArray(), ct); + new ReadValueIdCollection(vars.Select(r => new ReadValueId { NodeId = ExpandedNodeId.ToNodeId(r.NodeId, session.NamespaceUris), AttributeId = Attributes.Value })), ct); var results = response.Results.ToList(); - for (var i = 0; i < vars.Count; i++) caps[vars[i].BrowseName.Name!] = Fmt(results[i].ClrValue()); + for (var i = 0; i < vars.Count; i++) caps[vars[i].BrowseName.Name!] = Fmt(results[i].Value); } var aggs = await BrowseAsync(session, ObjectIds.HistoryServerCapabilities_AggregateFunctions, ReferenceTypeIds.Organizes, ct); caps["AggregateFunctions"] = string.Join(",", aggs.Select(r => r.BrowseName.Name).OrderBy(n => n, StringComparer.Ordinal)); @@ -472,9 +472,9 @@ private static async Task> BrowseAsync(ISession session, NodeId node, NodeId referenceType, CancellationToken ct) { var response = await session.BrowseAsync(null, null, 0, - new BrowseDescription[] + new BrowseDescriptionCollection { - new() + new BrowseDescription { NodeId = node, BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = referenceType, IncludeSubtypes = true, NodeClassMask = 0, ResultMask = (uint)BrowseResultMask.All, @@ -483,7 +483,7 @@ return response.Results[0].References.ToList(); } - private static DateTime? Ts(DateTimeUtc t) => (DateTime)t == DateTime.MinValue ? null : DateTime.SpecifyKind((DateTime)t, DateTimeKind.Utc); + private static DateTime? Ts(DateTime t) => t == DateTime.MinValue ? null : DateTime.SpecifyKind(t, DateTimeKind.Utc); private static string Name(StatusCode code) => code.SymbolicId is { Length: > 0 } s ? s : $"0x{code.Code:X8}";