Close IIS deploy rigor gaps (Phase 3.5 hardening)
Summary
Audit of the Octopus-mirrored PS1 against the existing test suite identified five reachable production paths that no E2E exercised. This PR fills each gap so every IIS branch the operator can hit has at least one real-host test asserting metabase state matches configuration. No production code changes — pure test additions.
What ships (9 new tests, all real-host high-fidelity)
| Gap | Coverage |
|---|---|
App pool identity = LocalSystem / NetworkService / LocalService / ApplicationPoolIdentity
|
RealIIS_AppPoolIdentityType_BuiltIn_AppliedToMetabase Theory across all 4 |
App pool identity = SpecificUser with domain credentials |
RealIIS_AppPoolIdentitySpecificUser_AppliesCredentialsToMetabase — stages a local Windows user via net user /add, asserts metabase reflects identityType + userName, cleans up account on Dispose |
Framework version = No Managed Code (empty managedRuntimeVersion) |
Promotes existing v2.0 Fact to a Theory covering v4.0 / v2.0 / No Managed Code. Pins the PS1's line 227-229 empty-string branch |
ExistingBindings = Merge |
RealIIS_ExistingBindingsMerge_PreservesPreExistingBindings — pre-creates site with 2 external bindings, redeploys with Merge + 1 configured binding, asserts BOTH survive |
Empty Bindings []
|
RealIIS_EmptyBindingsArray_DeploysSiteWithoutOperatorBindings — deploys with empty array, StartWebSite=False; pins that the site still gets created (zero-binding path is a real operator workflow with Merge mode) |
Test count
- Real-host E2E: 16 → 25 (+9 from Phase 3.5)
- Squid unit tests: unchanged (rigor is at runtime tier)
- Squid pipeline E2E: unchanged
New test infrastructure
-
IISTestContext.PickAdditionalFreePort()— second free localhost port (needed by Merge test which pre-creates a binding on port A and deploys to port B) -
IISTestContext.StageLocalWindowsUser()— creates account with strong password, registers fornet user /deletecleanup. Used by SpecificUser test - New cleanup pass in
Dispose()for_localUsersToClean
Test plan
-
dotnet test --filter Category=IISDeployE2Eon macOS — 25 tests skip cleanly via OS guard -
dotnet buildforSquid.WindowsTentacleE2ETests— 0 errors -
CI run on windows-latest: validate all 9 new tests against real IIS metabase,Get-WebBinding,Get-ItemProperty IIS:\AppPools\...processModel.identityTyperound-trip
Why this matters
Closes the gap between "common-case rigorous" and "every PS1 branch exercised at least once". After this PR an operator hitting any of these less-common but legitimate options (enterprise SpecificUser pools, classic-ASP "No Managed Code", operator-staged bindings via Merge) is no longer the first real user to hit the path — the CI suite already proved it works end-to-end on a real Windows host.
Out of scope
- Phase 4 — WebApplication + VirtualDirectory (constants + PS1 branches present, still dormant)
- Phase 5 — Path B Tentacle-side
\$SquidParametersbootstrap
Breaking-change risk
None. Pure test additions. The one existing Fact (RealIIS_AppPoolFrameworkVersionV2_AppliedToMetabase) is refactored to a Theory that includes the original v2.0 case verbatim — coverage preserved, not replaced.