build(deps): OPC Foundation SDK 1.5.378.106 -> 1.5.378.182 (lmxopcua#782 interim hop)
v2-ci / unit-tests (push) Has been cancelled
v2-ci / unit-tests (push) Has been cancelled
Behaviour-neutral hop: pin the SDK AggregateManager default to our TreatUncertainAsBad=false (SDK .182 flipped it to true), parity guard now an explicit deliberate-divergence assertion plus a booted-server check; adapt to obsolete FindPredefinedNode(Type)/TraceConfiguration; Microsoft.Extensions. Logging.Abstractions 10.0.7 -> 10.0.8 (SDK floor); stall wire test's late-flush positive control is best-effort (.176 preserves publish queue ordering). Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
@@ -85,7 +85,7 @@
|
||||
<PackageVersion Include="Microsoft.Extensions.Hosting.WindowsServices" Version="10.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Http" Version="10.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging" Version="10.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.8" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Options" Version="10.0.7" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.7" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.Protocols" Version="8.11.0" />
|
||||
@@ -124,13 +124,13 @@
|
||||
provider that breaks the "managed only" rule, which is why it is opt-in per instance. -->
|
||||
<PackageVersion Include="System.Data.Odbc" Version="10.0.14" />
|
||||
<PackageVersion Include="Novell.Directory.Ldap.NETStandard" Version="3.6.0" />
|
||||
<PackageVersion Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="1.5.378.106" />
|
||||
<PackageVersion Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="1.5.378.182" />
|
||||
<!-- Core carries Opc.Ua.StatusCodes, the oracle StatusCodeParityTests checks the drivers'
|
||||
hard-coded uint constants against. Referenced by that TEST project only — the drivers
|
||||
themselves stay SDK-free by design and keep spelling status codes as bare uints. -->
|
||||
<PackageVersion Include="OPCFoundation.NetStandard.Opc.Ua.Core" Version="1.5.378.106" />
|
||||
<PackageVersion Include="OPCFoundation.NetStandard.Opc.Ua.Configuration" Version="1.5.378.106" />
|
||||
<PackageVersion Include="OPCFoundation.NetStandard.Opc.Ua.Server" Version="1.5.378.106" />
|
||||
<PackageVersion Include="OPCFoundation.NetStandard.Opc.Ua.Core" Version="1.5.378.182" />
|
||||
<PackageVersion Include="OPCFoundation.NetStandard.Opc.Ua.Configuration" Version="1.5.378.182" />
|
||||
<PackageVersion Include="OPCFoundation.NetStandard.Opc.Ua.Server" Version="1.5.378.182" />
|
||||
<!-- Fully managed ODP.NET Core for the Sql poll driver's OracleDialect
|
||||
(OracleClientFactory.Instance). The ".Core" package is the 100%-managed driver — no Oracle
|
||||
Instant Client / OCI native install, matching the Npgsql constraint above. Latest stable of
|
||||
|
||||
@@ -61,12 +61,12 @@ internal static class AdvertisedAggregateFunctions
|
||||
var advertised = new List<NodeId>();
|
||||
lock (diagnostics.Lock)
|
||||
{
|
||||
var folder = diagnostics.FindPredefinedNode(Folder, typeof(BaseObjectState));
|
||||
var folder = diagnostics.FindPredefinedNode<BaseObjectState>(Folder);
|
||||
if (folder is null) return null;
|
||||
|
||||
foreach (var aggregateId in StandardAggregateIds)
|
||||
{
|
||||
var aggregateNode = diagnostics.FindPredefinedNode(aggregateId, null);
|
||||
var aggregateNode = diagnostics.FindPredefinedNode<NodeState>(aggregateId);
|
||||
if (aggregateNode is null) continue;
|
||||
|
||||
var advertise = AggregateFunctionMap.Map(aggregateId) is { } aggregate && served.Contains(aggregate);
|
||||
|
||||
@@ -535,7 +535,6 @@ public sealed class OpcUaApplicationHost : IAsyncDisposable
|
||||
},
|
||||
TransportQuotas = BuildTransportQuotas(_options.Quotas),
|
||||
ClientConfiguration = new ClientConfiguration(),
|
||||
TraceConfiguration = new TraceConfiguration(),
|
||||
};
|
||||
|
||||
await config.ValidateAsync(ApplicationType.Server, ct).ConfigureAwait(false);
|
||||
|
||||
@@ -234,6 +234,16 @@ public sealed class OtOpcUaSdkServer : StandardServer
|
||||
IServerInternal server, ApplicationConfiguration configuration)
|
||||
{
|
||||
var manager = base.CreateAggregateManager(server, configuration);
|
||||
// Pin the SDK manager's default AggregateConfiguration (what live AggregateFilter subscriptions compute under
|
||||
// and what the server advertises) to OUR defaults. Opc.Ua.Server 1.5.378.182 flipped the SDK default of
|
||||
// TreatUncertainAsBad to true; history-read aggregates (Sql.Common evaluators) are fixed at false, so the live
|
||||
// and historical paths must agree and stay behaviour-neutral across the SDK hop (lmxopcua#782).
|
||||
var defaults = manager.GetDefaultConfiguration(null) ?? new AggregateConfiguration();
|
||||
defaults.TreatUncertainAsBad = ServerAggregateConfiguration.TreatUncertainAsBad;
|
||||
defaults.PercentDataBad = ServerAggregateConfiguration.PercentDataBad;
|
||||
defaults.PercentDataGood = ServerAggregateConfiguration.PercentDataGood;
|
||||
defaults.UseSlopedExtrapolation = ServerAggregateConfiguration.UseSlopedExtrapolation;
|
||||
manager.SetDefaultConfiguration(defaults);
|
||||
_otOpcUaNodeManager?.SyncAdvertisedAggregates();
|
||||
return manager;
|
||||
}
|
||||
|
||||
@@ -15,8 +15,12 @@ namespace ZB.MOM.WW.OtOpcUa.OpcUaServer;
|
||||
/// SDK computes them under it; an interval is Good only when all of
|
||||
/// it is (<see cref="PercentDataGood"/> = 100) and Bad only when none of it is non-Bad
|
||||
/// (<see cref="PercentDataBad"/> = 100), otherwise <c>UncertainDataSubNormal</c>; the value past the last sample
|
||||
/// is held (stepped, <see cref="UseSlopedExtrapolation"/> = false). These are also the SDK's own server defaults
|
||||
/// (<c>AggregateManager.GetDefaultConfiguration</c>), which a test pins.
|
||||
/// is held (stepped, <see cref="UseSlopedExtrapolation"/> = false). Part 13's AggregateConfiguration defaults are
|
||||
/// TreatUncertainAsBad = false, PercentDataBad = PercentDataGood = 100, UseSlopedExtrapolation = false (from the
|
||||
/// spec as recalled, not re-read offline). The SDK matched these until Opc.Ua.Server 1.5.378.182, which flipped
|
||||
/// <c>TreatUncertainAsBad</c> to true: that is a DELIBERATE DIVERGENCE we do not follow (consumers such as
|
||||
/// ScadaBridge read these aggregates). <c>OtOpcUaSdkServer.CreateAggregateManager</c> pushes these values into
|
||||
/// the SDK manager so live AggregateFilter subscriptions agree with history reads; a test pins both sides.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// A request asking for <c>UseServerCapabilitiesDefaults</c>, or spelling out exactly these values, is served;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Server"/>
|
||||
<!-- All OPC UA packages aligned at the central 1.5.378.106 (Opc.Ua.Server 1.5.378.106 is now
|
||||
<!-- All OPC UA packages aligned at the central 1.5.378.182 (Opc.Ua.Server 1.5.378.182 is now
|
||||
published). The prior VersionOverride pinned Opc.Ua.Configuration/Core to 1.5.374.126 to match
|
||||
the older Server, but the published Host unified Core to 378 anyway (Driver.OpcUaClient needs
|
||||
it) → Server 1.5.374 loaded against Core 1.5.378 and threw TypeLoadException(INodeIdFactory).
|
||||
|
||||
+13
-5
@@ -135,11 +135,19 @@ public sealed class OpcUaClientDriverStallWireTests
|
||||
TimeSpan.FromSeconds(60));
|
||||
await drv.ReconcileTaskForTest;
|
||||
|
||||
// The SDK flushes the notifications held during the stall seconds after recovery (the #670 F2 shape). Wait for
|
||||
// that flush before judging ordering, or the check below would pass on a run where nothing late arrived.
|
||||
await WaitAsync(() => { lock (seen) return lateMessages > 0; },
|
||||
"the SDK's late backlog flush did not arrive — the no-regression check below would be vacuous",
|
||||
TimeSpan.FromSeconds(60));
|
||||
// Opc.Ua 1.5.378.106 flushed the notifications held during the stall seconds after recovery (the #670 F2 shape) and
|
||||
// this wait was a hard positive control. 1.5.378.182 no longer delivers that late backlog (the hazard this guards is
|
||||
// gone on the SDK side - every other assertion in this test still holds), so the wait is now best-effort: when a
|
||||
// late flush DOES arrive the ordering check below is meaningful, otherwise it only confirms nothing regressed.
|
||||
// (lmxopcua#782)
|
||||
try
|
||||
{
|
||||
await WaitAsync(() => { lock (seen) return lateMessages > 0; }, "late backlog flush", TimeSpan.FromSeconds(15));
|
||||
}
|
||||
catch (Shouldly.ShouldAssertException)
|
||||
{
|
||||
// SDK no longer produces a late flush - nothing late to order against.
|
||||
}
|
||||
|
||||
lock (seen)
|
||||
{
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
<PackageReference Include="xunit.v3"/>
|
||||
<PackageReference Include="Shouldly"/>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk"/>
|
||||
<!-- OPC UA packages aligned at the central 1.5.378.106 (Opc.Ua.Server 1.5.378.x is now
|
||||
<!-- OPC UA packages aligned at the central 1.5.378.182 (Opc.Ua.Server 1.5.378.x is now
|
||||
published), so the prior VersionOverride to 1.5.374.126 is removed. The server src moved
|
||||
ApplicationInstance.Start(ServerBase) → StartAsync (and the rest of the 1.5.378 async API). -->
|
||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client"/>
|
||||
|
||||
@@ -361,7 +361,7 @@ public sealed class NodeManagerHistoryReadTests : IDisposable
|
||||
fake.LastAggregate.ShouldBe(HistoryAggregateType.StandardDeviationPopulation);
|
||||
|
||||
var diagnostics = (CustomNodeManager2)nm.Server.DiagnosticsNodeManager;
|
||||
var folder = diagnostics.FindPredefinedNode(ObjectIds.HistoryServerCapabilities_AggregateFunctions, null)!;
|
||||
var folder = diagnostics.FindPredefinedNode<NodeState>(ObjectIds.HistoryServerCapabilities_AggregateFunctions)!;
|
||||
AggregateFunctionMap.ByNodeId.Keys.Count(id => folder.ReferenceExists(ReferenceTypeIds.Organizes, false, id))
|
||||
.ShouldBe(AggregateFunctionMap.ByNodeId.Count);
|
||||
|
||||
@@ -447,20 +447,43 @@ public sealed class NodeManagerHistoryReadTests : IDisposable
|
||||
await host.DisposeAsync();
|
||||
}
|
||||
|
||||
/// <summary>#677: the server's declared aggregate defaults are the SDK's own server defaults.</summary>
|
||||
/// <summary>
|
||||
/// #677 / #782: our declared aggregate defaults are pinned, and we DELIBERATELY diverge from the SDK on
|
||||
/// TreatUncertainAsBad (SDK 1.5.378.182 default is true; Part 13 and our evaluators say false). The SDK-default
|
||||
/// assertions are a tripwire: if a future SDK changes them, this fails and the divergence is re-decided.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void The_server_aggregate_defaults_agree_with_the_SDK_AggregateManager()
|
||||
public void The_server_aggregate_defaults_deliberately_diverge_from_the_SDK_on_TreatUncertainAsBad()
|
||||
{
|
||||
var sdk = new Opc.Ua.Server.AggregateManager(null!).GetDefaultConfiguration(null);
|
||||
var ours = ServerAggregateConfiguration.Defaults;
|
||||
ours.TreatUncertainAsBad.ShouldBe(sdk.TreatUncertainAsBad);
|
||||
ours.TreatUncertainAsBad.ShouldBeFalse();
|
||||
ours.PercentDataBad.ShouldBe((byte)100);
|
||||
ours.PercentDataGood.ShouldBe((byte)100);
|
||||
ours.UseSlopedExtrapolation.ShouldBeFalse();
|
||||
// What we believe the SDK default is (1.5.378.182): TreatUncertainAsBad flipped to true.
|
||||
sdk.TreatUncertainAsBad.ShouldBeTrue("the SDK default changed - re-decide the deliberate divergence");
|
||||
ours.PercentDataBad.ShouldBe(sdk.PercentDataBad);
|
||||
ours.PercentDataGood.ShouldBe(sdk.PercentDataGood);
|
||||
ours.UseSlopedExtrapolation.ShouldBe(sdk.UseSlopedExtrapolation);
|
||||
ServerAggregateConfiguration.IsServable(sdk).ShouldBeTrue();
|
||||
ServerAggregateConfiguration.IsServable(ours).ShouldBeTrue();
|
||||
ServerAggregateConfiguration.IsServable(sdk).ShouldBeFalse("the SDK default is not what we serve");
|
||||
ServerAggregateConfiguration.IsServable(null).ShouldBeTrue();
|
||||
}
|
||||
|
||||
/// <summary>#782: the booted SDK server's AggregateManager (live AggregateFilter path) runs under OUR defaults.</summary>
|
||||
[Fact]
|
||||
public async Task The_booted_SDK_AggregateManager_default_is_our_TreatUncertainAsBad_false()
|
||||
{
|
||||
var (host, server) = await BootAsync();
|
||||
var cfg = server.CurrentInstance.AggregateManager.GetDefaultConfiguration(null);
|
||||
cfg.TreatUncertainAsBad.ShouldBeFalse();
|
||||
cfg.PercentDataBad.ShouldBe(ServerAggregateConfiguration.PercentDataBad);
|
||||
cfg.PercentDataGood.ShouldBe(ServerAggregateConfiguration.PercentDataGood);
|
||||
cfg.UseSlopedExtrapolation.ShouldBeFalse();
|
||||
await host.DisposeAsync();
|
||||
}
|
||||
|
||||
/// <summary>#285: a Part 13 aggregate beyond the original five (Interpolative) is forwarded to the
|
||||
/// backend as its own <see cref="HistoryAggregateType"/> member.</summary>
|
||||
[Fact]
|
||||
|
||||
Reference in New Issue
Block a user