Add Phase 13 PR-3: Windows real-binary polling agent E2E
Summary
- New high-fidelity E2E
R1h_RealBinary_PollingAgent_ScriptDispatchRoundTripsThroughHalibut— Windows mirror of Linux R1h. Drives the realdotnet publish'dSquid.Tentacle.exeas a polling agent againstStubSquidServer, then dispatches a real PowerShell script through the polling channel and asserts the output round-trips. - Closes the coverage gap between
TentacleRegisterE2ETests(in-process production class) andTentacleDeployE2ETests(StubAgent wrapper) — neither exercises the real binary's polling code path. - Tier
🟢 H per Rule 12.4 — zero mocks at the production-code layer.
Stacking
Stacks on top of #270 (PR-2) which adds WindowsTentacleBinaryFixture. Once #270 merges, GitHub will auto-retarget this PR's base branch to main. Local-author flow if needed:
git rebase --onto origin/main phase13.real-binary-integration-pr2-windows-binary-fixture
SCM gap surfaced
Squid.Tentacle's Program.cs has no UseWindowsService() / ServiceBase integration. SCM-launched start (the production deployment shape) would time out at ERROR_SERVICE_REQUEST_TIMEOUT because the binary doesn't register a service control handler. This is a real production gap — operators following the documented service install + sc start workflow on Windows would see the service fail to reach RUNNING.
Tracked as a separate production-fix task. Once that lands, an SCM-launched variant of this test can be added. PR-3 uses Process.Start to validate the same polling code path which is the primary value of Phase 13.
Mechanism
-
StubSquidServer.StartAsync— full Halibut listener onPollingUri+ REST register onServerUri, real self-signed cert - Pre-create instance via
InstanceRegistry(production binary'sregisterrequires it; matchesTentacleRegisterE2ETests) - Real binary
register --comms-url=stub.PollingUri— Polling mode, persists config with stub'sServerThumbprint - Extract agent thumbprint + subscriptionId from
stub.ReceivedRegistrations[0] -
stub.TrustAgent(thumbprint)— must come beforerun(TLS handshake otherwise rejects the agent's cert) -
binary.StartLongRunning("run", "--instance", ...)— real binary opens outbound polling channel to stub - Wait for
stub.ProbeCapabilitiesPollingAsyncto succeed (Windows handshake takes 2-5s due to .NET startup + cert store traversal) -
THE PIN:
stub.DispatchAndObservePollingAsyncwithStart-Sleep -Seconds 1; Write-Host '<marker>'— assert exit 0 + marker - Cleanup:
Process.Killthe long-running binary, delete config + remove instance
What this catches that prior Windows tests miss
-
register→runconfig round-trip on Windows (PlatformPaths resolution diverges from Linux's/etc/squid-tentacle/pattern) -
TentacleHalibutHost.StartPollingregression on Windows (cert store traversal,IPAddress.Anybinding) -
LocalScriptServicePowerShell spawn regression on real-binary path (vsStubAgent's in-process wrapping of the same service) - ProcessOutput streaming through Halibut on the real Windows binary
Test plan
-
CI on windows-latestrunsCategory=WindowsTentacleBinaryE2E:-
R1h_RealBinary_PollingAgent_ScriptDispatchRoundTripsThroughHalibutpasses -
Binary_Version_PrintsBuildVersionStamp(PR-2 smoke) still green -
Binary_Help_ProducesUsageOutput(PR-2 smoke) still green
-
-
dotnet build tests/Squid.WindowsTentacleE2ETests/Squid.WindowsTentacleE2ETests.csproj— 0 errors
Phase 13 status after this lands
| PR | Status | Coverage |
|---|---|---|
| #269 (PR-1) |
|
Linux real-binary as polling agent (systemd-started) |
| #270 (PR-2) |
|
WindowsTentacleBinaryFixture + smoke |
| #271 (this, PR-3) |
|
Windows real-binary as polling agent (Process.Start) |
| PR-4 | pending | Keep-alive / soak — multi-second probe stability for both OSes |