Skip to content

test(stack): share one state root across the integration suite - #6956

Open
jgoux wants to merge 6 commits into
developfrom
test/stack-shared-integration-state-root
Open

jgoux wants to merge 6 commits into
developfrom
test/stack-shared-integration-state-root

Conversation

@jgoux

@jgoux jgoux commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

The stack integration suite gave almost every test its own temporary state root. Automatic public ports skip only ports saved by stacks under the same root, so a concurrently running file could take the port a stopped composition in another file had saved. The restart then failed with Public port … is already in use, as seen intermittently in Supabase.native.integration.test.ts ("promotes a stopped database composition without replacing its identity or data"). An occupied saved port reporting a conflict is the intended product behaviour; the suite was outside the supported topology of one state root per host.

The suite now follows that topology:

  • A vitest globalSetup for the integration project creates one state root per run and provides it via inject. Every test that binds real listeners on automatic public ports (including composition creation, which binds immediately) uses it with unique stack IDs.
  • Tests that only simulate allocation, bind no public ports, or assert the exact contents of a root (Sweep, State, HostProcess, destroy/rollback, container shutdown and sweep retry, and the malformed-sibling Ports cases) keep private roots.
  • In-process owner doubles register through registerLeased, which takes the stack lease before saving, like runStackHost. Without it, another file's orphan sweep could reclaim a stack whose in-process owner holds no lease.
  • Whole-root discover and snapshot-descriptor assertions in migrated files check the test's own stacks.
  • Native backend ports come from the same span and skip only the claims they are given, so service tests that reserve them read the shared root's claims, and the native reservation tests in Ports.integration.test.ts avoid shared claimed ports while still targeting the port under test.
  • makeDockerDatabaseRoot can place a Docker data root under the shared root. The shared root's Docker volume is removed by the existing per-run, label-based cleanup in tests/docker-volume-run.ts.
  • Fixed test ports inside the automatic span move below 20000.
  • A new Ports regression proves that a competitor whose first scan candidate is a stopped sibling's saved port gets it in a separate root but skips it in the same root.

CommandRunner.native-cleanup.integration.test.ts downloaded psql into a fresh cache inside its test body and timed out on slow downloads; it now uses the shared artifact cache and prepares psql in a beforeAll hook.

Concurrent integration runs from other checkouts on the same host still use separate roots and remain outside the supported topology.

Integration files created private state roots, so a concurrent file could
auto-allocate a public port that a stopped composition in another file had
saved, and the restart then reported the port as occupied. The suite now
matches the supported topology of one state root per host.

- A vitest globalSetup creates one state root per run and provides it to
  every test that binds real listeners on automatic public ports; those
  tests use unique stack IDs.
- Tests that only simulate allocation, bind no public ports, or assert the
  exact contents of a root keep private roots.
- In-process owner doubles take the stack lease before registering, like
  the product owner, so another file's orphan sweep cannot reclaim them.
- Whole-root discovery and snapshot assertions are scoped to the test's
  own stacks.
- The shared root's Docker snapshot-cache volume is removed once by the
  suite teardown instead of per test.
- Fixed test ports move below the automatic span.
- A Ports regression covers a stopped sibling's saved port that is the
  competitor's first scan candidate.

Concurrent integration runs from other checkouts on the same host use
separate roots and remain outside the supported topology.
@jgoux
jgoux requested a review from a team as a code owner October 2, 2026 08:42
@jgoux jgoux self-assigned this Oct 2, 2026
jgoux added 5 commits October 2, 2026 10:50
…integration-state-root

# Conflicts:
#	packages/stack/tests/docker-fixture.ts
#	packages/stack/vitest.config.ts
…integration-state-root

# Conflicts:
#	packages/stack/src/Ports.integration.test.ts
The native workload cleanup test used a fresh artifact cache, so every
run downloaded psql inside the test body and timed out whenever the
download was slow. It now uses the shared artifact cache and prepares
psql in a beforeAll hook, so the test timeout covers only the cleanup
retries it asserts.
Native backend ports now come from the same span as automatic public
ports and skip only the claims they are given. Service tests that passed
no claims, and an owner test that starts a native service on a private
root, could take a stopped shared-root stack's saved port, which is the
collision the shared root removes.

- Service integration tests that can reserve native backend ports read
  the shared root's claims.
- The Owner test that starts REST natively uses the shared root.
- The native reservation, exclusion and loopback Ports tests avoid shared
  claimed ports and start their second scan at the port under test, so a
  released shared claim cannot satisfy their assertions.
- The sibling regression keeps both stacks in the shared root and takes
  the colliding port from the actual allocation.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant