Skip to content

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 real dotnet publish'd Squid.Tentacle.exe as a polling agent against StubSquidServer, 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) and TentacleDeployE2ETests (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

  1. StubSquidServer.StartAsync — full Halibut listener on PollingUri + REST register on ServerUri, real self-signed cert
  2. Pre-create instance via InstanceRegistry (production binary's register requires it; matches TentacleRegisterE2ETests)
  3. Real binary register --comms-url=stub.PollingUri — Polling mode, persists config with stub's ServerThumbprint
  4. Extract agent thumbprint + subscriptionId from stub.ReceivedRegistrations[0]
  5. stub.TrustAgent(thumbprint) — must come before run (TLS handshake otherwise rejects the agent's cert)
  6. binary.StartLongRunning("run", "--instance", ...) — real binary opens outbound polling channel to stub
  7. Wait for stub.ProbeCapabilitiesPollingAsync to succeed (Windows handshake takes 2-5s due to .NET startup + cert store traversal)
  8. THE PIN: stub.DispatchAndObservePollingAsync with Start-Sleep -Seconds 1; Write-Host '<marker>' — assert exit 0 + marker
  9. Cleanup: Process.Kill the long-running binary, delete config + remove instance

What this catches that prior Windows tests miss

  • register → run config round-trip on Windows (PlatformPaths resolution diverges from Linux's /etc/squid-tentacle/ pattern)
  • TentacleHalibutHost.StartPolling regression on Windows (cert store traversal, IPAddress.Any binding)
  • LocalScriptService PowerShell spawn regression on real-binary path (vs StubAgent's in-process wrapping of the same service)
  • ProcessOutput streaming through Halibut on the real Windows binary

Test plan

  • CI on windows-latest runs Category=WindowsTentacleBinaryE2E:
    • R1h_RealBinary_PollingAgent_ScriptDispatchRoundTripsThroughHalibut passes
    • 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) 🟢 merged Linux real-binary as polling agent (systemd-started)
#270 (PR-2) 🟢 awaiting merge WindowsTentacleBinaryFixture + smoke
#271 (this, PR-3) 🟡 awaiting CI Windows real-binary as polling agent (Process.Start)
PR-4 pending Keep-alive / soak — multi-second probe stability for both OSes

🤖 Generated with Claude Code

Merge request reports

Loading