9251c564c1
Closes the latent + minor + test-discipline items left after Wave 4. Updates
the re-review doc with a final resolution table — every actionable finding
now marked Resolved or Accepted with rationale.
NM3 — _supervisorCts leaks on re-Start
StartAsync now disposes the previous CTS before reassigning. Idempotent:
a try/catch (ObjectDisposedException) covers the very-first-Start case
where the field-init CTS is still fresh.
NM4 — W2.15 TCS is single-shot
_firstAttemptCompleted is no longer readonly; StartAsync re-creates it
after the W2.16 guard so a re-Started supervisor's
WaitForInitialBindAttemptAsync doesn't observe the previous run's signal.
Nm6 — _admin GetService<> returns null silently
ProxyWorker.ExecuteAsync now logs a Warning when admin isn't registered.
Preserves the loud-failure intent from the original IHostedService
registration without forcing test hosts to wire admin.
Nm7 — AdminEndpointHost.DisposeAsync no double-dispose guard
Added a volatile bool _disposed flag with an early-return at the top of
DisposeAsync. Symmetry with PlcMultiplexer; protects against
ProxyWorker.StopAsync explicitly disposing then DI disposing the singleton
again on host shutdown.
T3 — RemoveInheritedAppsettings only fires on Build
AfterTargets="Build;Publish" + a second Delete against $(PublishDir)
so a `dotnet publish` against the test csproj doesn't ship the example
PLCs from the linked install template.
T4 — Stale TryAttachOrCreate_*_ReturnsTrue_* test method names
Renamed to AttachOrCreate_*_WasNew{True,False} after W3 dropped the bool
return.
Accepted (with rationale documented in ReReviewAfterRemediation.md):
Nm2 — CoalescedHit semantic is per-design
Nm4 — _lastBindError preservation on clean exit is intentional forensics
Nm5 — EventLogBridge has no injectable logger
Nm8 — Cosmetic log noise
T1 — Reflection on private fields documented as maintenance trap
Tests: 387 pass / 0 fail.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
47 lines
2.3 KiB
XML
47 lines
2.3 KiB
XML
<!-- xunit version: v3 (xunit.v3 3.2.2) — chosen because a stable release exists on NuGet as of 2026-05-13 -->
|
|
<!-- NModbus 3.0.83 — chosen for small footprint, net10.0 compatibility, and synchronous/async FC03/FC16 API
|
|
that maps directly to the Modbus PDU function codes used in smoke and e2e tests.
|
|
Added in Phase 01 as the Modbus TCP client for all simulator-backed tests. -->
|
|
<Project Sdk="Microsoft.NET.Sdk">
|
|
|
|
<PropertyGroup>
|
|
<TargetFramework>net10.0</TargetFramework>
|
|
<Nullable>enable</Nullable>
|
|
<ImplicitUsings>enable</ImplicitUsings>
|
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
|
<IsPackable>false</IsPackable>
|
|
<IsTestProject>true</IsTestProject>
|
|
<RootNamespace>Mbproxy.Tests</RootNamespace>
|
|
</PropertyGroup>
|
|
|
|
<ItemGroup>
|
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
|
|
<!-- xunit v3: stable as of 2026-05-13 -->
|
|
<PackageReference Include="xunit.v3" Version="3.2.2" />
|
|
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
<PrivateAssets>all</PrivateAssets>
|
|
</PackageReference>
|
|
<PackageReference Include="Shouldly" Version="4.3.0" />
|
|
<!-- NModbus: Modbus TCP client for simulator smoke tests and e2e tests (Phase 01+) -->
|
|
<PackageReference Include="NModbus" Version="3.0.83" />
|
|
</ItemGroup>
|
|
|
|
<ItemGroup>
|
|
<ProjectReference Include="..\..\src\Mbproxy\Mbproxy.csproj" />
|
|
</ItemGroup>
|
|
|
|
<!-- Phase 12 (W2.21) — the linked appsettings.json from Mbproxy.csproj propagates to
|
|
the test bin via the project reference. Tests build their own in-memory
|
|
configurations and must not pick up the shipped template's example PLCs. The
|
|
Target deletes the inherited file from both the build output AND the publish
|
|
payload (W4 / T3 — adds Publish so a `dotnet publish` against this csproj for a
|
|
packaged self-test would not leak the template's example PLCs into the published
|
|
bundle). -->
|
|
<Target Name="RemoveInheritedAppsettings" AfterTargets="Build;Publish">
|
|
<Delete Files="$(OutputPath)appsettings.json" Condition="Exists('$(OutputPath)appsettings.json')" />
|
|
<Delete Files="$(PublishDir)appsettings.json" Condition="'$(PublishDir)' != '' AND Exists('$(PublishDir)appsettings.json')" />
|
|
</Target>
|
|
|
|
</Project>
|