Resolve 6 of 7 stability review findings and close test coverage gaps

Fixes P1 StaComThread hang (crash-path faulting via WorkItem queue), P1 subscription
fire-and-forget (block+log or ContinueWith on 5 call sites), P2 continuation point
leak (PurgeExpired on Retrieve/Release), P2 dashboard bind failure (localhost prefix,
bool Start), P3 background loop double-start (task handles + join on stop in 3 files),
and P3 config logging exposure (SqlConnectionStringBuilder password masking). Adds
FakeMxAccessClient fault injection and 12 new tests. Documents required runtime
assemblies in ServiceHosting.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-04-07 15:37:27 -04:00
parent a28600ab1b
commit 95ad9c6866
16 changed files with 692 additions and 52 deletions

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Shouldly;
@@ -13,6 +14,9 @@ namespace ZB.MOM.WW.LmxOpcUa.Tests.MxAccess
/// </summary>
public class StaComThreadTests : IDisposable
{
[DllImport("user32.dll")]
private static extern void PostQuitMessage(int nExitCode);
private readonly StaComThread _thread;
/// <summary>
@@ -101,5 +105,20 @@ namespace ZB.MOM.WW.LmxOpcUa.Tests.MxAccess
results.Count.ShouldBe(3);
}
/// <summary>
/// Confirms that after the message pump exits, subsequent RunAsync calls throw instead of hanging.
/// </summary>
[Fact]
public async Task RunAsync_AfterPumpExit_ThrowsInsteadOfHanging()
{
// Kill the pump from inside by posting WM_QUIT
await _thread.RunAsync(() => PostQuitMessage(0));
await Task.Delay(100); // let pump exit
_thread.IsRunning.ShouldBe(false);
Should.Throw<InvalidOperationException>(() =>
_thread.RunAsync(() => { }).GetAwaiter().GetResult());
}
}
}