Add Phase 13 PR-1: Linux real-binary polling agent E2E
Summary
- New high-fidelity E2E
R1h_RealBinary_PollingAgent_ScriptDispatchRoundTripsThroughHalibutthat drives the realdotnet publish'd Squid.Tentacle binary as a polling agent againstStubSquidServer(real Halibut listener + REST register), then dispatches a real script through the polling channel and asserts the output round-trips. - Closes the coverage gap between B3h-Linux (register → service install → systemd "active" but never exercises polling) and LD1h–LD14h (Halibut dispatch + bash spawn but uses the in-process
StubAgentwrapper, not the real binary). - Tier
🟢 H per Rule 12.4 — zero mocks at the OS layer. Real binary, real systemd unit, real Halibut RPC over loopback TCP, real bash spawn.
Test plan
-
CI on ubuntu-latestrunsCategory=LinuxTentacleBinaryE2EandR1h_RealBinary_PollingAgent_ScriptDispatchRoundTripsThroughHalibutpasses -
Test exercises: register polling → service install → systemctl active → ProbeCapabilitiesPolling success → DispatchAndObservePolling round-trip -
Cleanup via service uninstall --purgeleaves/etc/squid-tentacle/instances/Default*removed -
dotnet build tests/Squid.LinuxTentacleE2ETests/Squid.LinuxTentacleE2ETests.csproj(0 errors, 283 pre-existing warnings)
Why this matters
Prior to this test the Linux suite had two disjoint coverage tiers:
| Existing test | What it pins | Gap |
|---|---|---|
B3h-Linux (B3h_FullWorkflow_RegisterAndServiceStart_ReachesActiveState) |
register → service install → systemd is-active=active
|
systemd "active" only confirms ExecStart launched. Polling channel connectivity + script-dispatch capability are not exercised. A regression where the real binary crashes silently after launch (Type=simple) would still pass. |
LD1h–LD14h (TentacleLinuxDeployE2ETests) |
Halibut script dispatch + LocalScriptService bash spawn + ProcessOutput round-trip |
Uses StubAgent (in-process wrapper around LocalScriptService) — the real binary's systemd-started polling code path is never exercised. |
R1h-Linux closes the gap: real binary, started by systemd, polling against the stub server, executing a real script that round-trips back. This is now the highest-fidelity E2E in the entire Linux suite.
What this catches that prior tests miss
-
register→runconfig round-trip regressions (e.g.Tentacle:ServerCommsUrlnot persisted →runfalls back to Listening mode and never polls) -
TentacleHalibutHost.StartPollingregressions (e.g. polling URI resolution: emptysubscriptionUrishould fall back topoll://<sub>/, regression makesnew Uri("")throw) - Halibut runtime trust-list propagation regression (server thumbprint loaded from config but not added to trust → TLS handshake fails)
-
LocalScriptServicespawn regression on the systemd-started path (different env vars / cwd than register-time invocation) - Server→agent ProcessOutput streaming regression in the real agent (vs
StubAgentwhich is the in-process wrapper)
Mechanism
-
StubSquidServer.StartAsync— full Halibut listener onPollingUri+ REST register onServerUri, real self-signed cert - Real binary
register --comms-url=stub.PollingUri --server=stub.ServerUri— Polling mode, persists config with stub'sServerThumbprint - Extract agent's thumbprint + subscriptionId from
stub.ReceivedRegistrations[0] -
stub.TrustAgent(thumbprint)— must come before service install (TLS handshake on stub-side rejects unknown agent certs) - Real binary
service install --service-name <name>— systemd writes unit, starts service, real binary'srunloads config,NoOpRegistrarreuses persistedServerCertificate,StartPollingconnects to stub - Wait for
systemctl is-active=active(binary launched) - Wait for
stub.ProbeCapabilitiesPollingAsyncto succeed — proves agent's polling channel actually connected (Halibut handshake takes 1-3s after runtime starts) -
THE PIN:
stub.DispatchAndObservePollingAsyncround-trip withsleep 1; echo '<marker>'— assert exit 0 + marker in logs - Cleanup:
service uninstall --purge→/etc/squid-tentacle/instances/Default*removed; defensive cleanup inRealBinaryPollingContext.DisposeAsynccovers failure paths
Phase 13 follow-ups (separate PRs)
- PR-2:
WindowsTentacleBinaryFixture(mirror Linux'sdotnet publishcache pattern) - PR-3: Windows real-binary as polling agent (mirror this test)
- PR-4: Keep-alive / soak — multi-second probe stability for both OSes (catch reconnection / drift bugs that single-shot tests miss)