feat(LinuxTentacleE2E): Phase 12.M.L.A.1 — Section A bootstrap + bogus-version exit-1
Summary
PIVOT to Section A install-tentacle.sh after the upgrade-flow phase closed (J.L.E.7–19, 13 PRs, 20 E2E tests, 1 production bug fixed). The user's original goal is "from install to deploy to lifecycle to upgrade — all functions confident" — install was the largest unfilled gap.
This is the smallest viable Section A scope: bogus version → exit 1. No successful install means no symlinks, no service install, no sudoers — minimal pollution surface, minimal cleanup, but real coverage of the .sh's argument parsing + URL construction + curl error handling.
Why bogus-version first (not happy path)
| Concern | Bogus version | Happy path |
|---|---|---|
| Pollution surface |
INSTALL_DIR only (failed mkdir, no other side effects) |
/etc/squid-tentacle, /var/lib/squid-tentacle, /usr/local/bin, sudoers, systemd unit, system user, apt sources |
| Cleanup complexity | Trivial | Significant matrix |
| Caught regression class | arg parsing, URL construction, curl errors, exit ordering | All of bogus-version + extract + chmod + symlink + service install + ownership + APT repo persistence |
| Risk on first PR | Low | Higher (each cleanup gap is a leak between tests) |
The fixture (LinuxInstallScriptContext) already implements full cleanup defensively (covering every production path the script writes to), so happy-path tests in J.M.L.A.2+ drop in additively without re-engineering.
Test mechanism
Configure LocalReleaseMirror to 404 BOTH the plain-version AND the v-prefixed download URLs (.sh tries both per lines 234-241). No tarball staged → both URL forms 404. .sh's download_ok wrapper retries 3× per URL; both URLs fail → exit 1 with "Could not download" error.
Assertions
| Assertion | Catches |
|---|---|
exitCode == 1 |
.sh exit-on-failure regression |
stdout contains "Could not download"
|
Operator-actionable diagnostic regression |
| stdout echoes the constructed URL | Operator can verify --version typo by reading the log |
INSTALL_DIR does NOT exist |
.sh's mkdir -p runs only after successful curl; presence = exit ordering regressed |
/etc/squid-tentacle does NOT exist |
Post-install block never ran |
/var/lib/squid-tentacle does NOT exist |
Same |
/usr/local/bin/squid-tentacle symlink does NOT exist |
Symlink creation is post-extract |
Infrastructure additions
-
LinuxInstallScriptContextfixture (sibling ofLinuxLifecycleContext; structurally different env vars + cleanup matrix so kept separate per ISP / Rule 7) -
LinuxTentacleE2ECategories.InstallScriptconstant -
tentacle-linux-e2e.ymlworkflow filter updated to include the new category in default (per CLAUDE.md trait-filter convention)
Cleanup matrix (forward-compatible with happy path)
Dispose() runs sudo rm -rf against:
-
INSTALL_DIR(per-test temp dir) /etc/squid-tentacle//var/lib/squid-tentacle//usr/local/bin/squid-tentacle/etc/apt/sources.list.d/squid.list/etc/apt/keyrings/squid.gpg/etc/apt/apt.conf.d/99-squid-direct.conf/etc/sudoers.d/squid-tentacle-upgrade/etc/systemd/system/squid-tentacle.service
Each is best-effort; missing paths are no-ops.
Fidelity tier
.sh against real bash + real curl + real LocalReleaseMirror returning real HTTP 404. No mocks at OS-resource layer.
Expected runtime: ~10s (curl retries 3× per URL × 2 URLs ~6s + apt-get update on first run ~3s; libicu typically pre-installed on ubuntu-latest so install_runtime_deps short-circuits).
Test plan
-
Linux E2E workflow runs Squid.LinuxTentacleE2ETests(manualworkflow_dispatchafter merge) -
A2u1_BogusVersion_ExitsOneWithCleanErrorAndNoPartialInstallpasses within ~15s -
No regression on existing 20 Linux E2E tests -
New trait Category=LinuxTentacleInstallScriptE2Ein workflow filter picks up the new test class