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

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:
Joseph Doherty
2026-11-09 22:47:58 -05:00
parent 42c73bfb83
commit 2da58d0360
9 changed files with 66 additions and 22 deletions
@@ -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)
{
@@ -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]