test(opcuaclient): slow server-side subscription delete keeps the stale-BadNoSubscription grace running from delete completion (lmxopcua#764)
v2-ci / unit-tests (push) Has been cancelled

Unsubscribe paths now delete through the existing DeleteSubscriptionAsync seam so a test can hold the delete open >grace. Mutation: dropping the post-delete restamp fails both slow-delete tests.

Claude-Session: https://claude.ai/code/session_01GT67AEHd2Acv1YPwGfXEoV
This commit is contained in:
Joseph Doherty
2026-11-10 05:05:18 -05:00
parent f201f16fd4
commit 70050c9d7e
2 changed files with 106 additions and 3 deletions
@@ -1242,7 +1242,7 @@ public sealed class OpcUaClientDriver : IDriver, ITagDiscovery, IReadable, IWrit
/// </summary>
internal TimeSpan TeardownBudget { get; set; } = TimeSpan.FromSeconds(4);
/// <summary>Test seam: the wire delete of one subscription. Production calls the SDK's silent delete.</summary>
/// <summary>Test seam: the wire delete of one subscription (unsubscribe + shutdown). Production calls the SDK's silent delete.</summary>
internal Func<Subscription, CancellationToken, Task> DeleteSubscriptionAsync { get; set; } =
static (subscription, ct) => subscription.DeleteAsync(silent: true, ct);
@@ -2050,7 +2050,7 @@ public sealed class OpcUaClientDriver : IDriver, ITagDiscovery, IReadable, IWrit
// RemoteSubscription is the exact instance that was added, so `-=` removes it
// cleanly.
DetachNotificationHandlers(rs.ItemHandlers);
try { await rs.Subscription.DeleteAsync(silent: true, cancellationToken).ConfigureAwait(false); }
try { await DeleteSubscriptionAsync(rs.Subscription, cancellationToken).ConfigureAwait(false); }
catch { /* best-effort — the subscription may already be gone on reconnect */ }
}
finally
@@ -2555,7 +2555,7 @@ public sealed class OpcUaClientDriver : IDriver, ITagDiscovery, IReadable, IWrit
// closure.
try { rs.EventItem.Notification -= rs.Handler; }
catch { /* best-effort */ }
try { await rs.Subscription.DeleteAsync(silent: true, cancellationToken).ConfigureAwait(false); }
try { await DeleteSubscriptionAsync(rs.Subscription, cancellationToken).ConfigureAwait(false); }
catch { /* best-effort — session may already be gone across a reconnect */ }
}
finally