Skip to content

Close IIS deploy rigor gaps (Phase 3.5 hardening)

Placeholder ppxd requested to merge feat/iis-deploy-rigor-hardening into main

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 for net user /delete cleanup. Used by SpecificUser test
  • New cleanup pass in Dispose() for _localUsersToClean

Test plan

  • dotnet test --filter Category=IISDeployE2E on macOS — 25 tests skip cleanly via OS guard
  • dotnet build for Squid.WindowsTentacleE2ETests — 0 errors
  • CI run on windows-latest: validate all 9 new tests against real IIS metabase, Get-WebBinding, Get-ItemProperty IIS:\AppPools\...processModel.identityType round-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 \$SquidParameters bootstrap

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.

Merge request reports

Loading