Skip to content

test: stabilize stopped sandbox websocket test#585

Merged
ColeMurray merged 2 commits intomainfrom
fix/websocket-sandbox-stopped-flake
May 2, 2026
Merged

test: stabilize stopped sandbox websocket test#585
ColeMurray merged 2 commits intomainfrom
fix/websocket-sandbox-stopped-flake

Conversation

@ColeMurray
Copy link
Copy Markdown
Owner

@ColeMurray ColeMurray commented May 2, 2026

Summary

  • Wait for the init-triggered warm sandbox attempt to settle before forcing the sandbox into stopped state.
  • Reuse the wait helper in the adjacent ready-state WebSocket test to avoid duplicating polling logic.

Testing

  • npm run test:integration -w @open-inspect/control-plane -- websocket-sandbox.test.ts
  • Re-ran the targeted integration file 5 times successfully.

Created with Open-Inspect

Summary by CodeRabbit

  • Tests
    • Improved sandbox-related test reliability by adding a polling mechanism to wait for target sandbox states before proceeding.
    • Updated tests to wait for failure/ready transitions to avoid race conditions in WebSocket scenarios.
    • Timeouts now surface the last observed sandbox state to aid troubleshooting.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 2, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: be07d25b-2180-4e06-bf2f-a0538fabd93d

📥 Commits

Reviewing files that changed from the base of the PR and between bf67d42 and 428900f.

📒 Files selected for processing (1)
  • packages/control-plane/test/integration/websocket-sandbox.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/control-plane/test/integration/websocket-sandbox.test.ts

📝 Walkthrough

Walkthrough

Adds a test helper waitForSandboxStatus (with a default timeout constant) that polls the sandbox DO table for a target status. Two integration tests are updated to use the helper to avoid race conditions by waiting for expected sandbox statuses before proceeding.

Changes

Test Race Condition Fixes

Layer / File(s) Summary
Data / Constants
packages/control-plane/test/integration/websocket-sandbox.test.ts
Adds DEFAULT_WAIT_FOR_SANDBOX_STATUS_TIMEOUT_MS constant for polling timeout.
Test Helper
packages/control-plane/test/integration/websocket-sandbox.test.ts
Adds waitForSandboxStatus(stub, status, timeoutMs?) that queries SELECT status FROM sandbox until it matches target or throws on timeout (includes last observed status in error).
Test Updates — "upgrade for stopped sandbox returns 410"
packages/control-plane/test/integration/websocket-sandbox.test.ts
Now awaits waitForSandboxStatus(stub, "failed") before seeding auth and setting sandbox status to "stopped".
Test Updates — "sandbox connect sets status to ready"
packages/control-plane/test/integration/websocket-sandbox.test.ts
Replaces bespoke polling loop with waitForSandboxStatus(stub, "failed") precondition and awaits waitForSandboxStatus(stub, "ready") after accepting the WebSocket.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related PRs

Suggested reviewers

  • open-inspect

Poem

🐰 I waited by the sandbox gate,
Polling ticks to check my fate.
No more races, status clear,
Tests hop on without a fear.
Bravo — cookies and a carrot plate.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly summarizes the main change: stabilizing a flaky websocket test for stopped sandboxes by improving test reliability through better async handling.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/websocket-sandbox-stopped-flake

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 2, 2026

Terraform Validation Results

Step Status
Format
Init
Validate

Note: Terraform plan was skipped because secrets are not configured. This is expected for external contributors. See docs/GETTING_STARTED.md for setup instructions.

Pushed by: @ColeMurray, Action: pull_request

Comment thread packages/control-plane/test/integration/websocket-sandbox.test.ts
open-inspect[bot]
open-inspect Bot previously requested changes May 2, 2026
Copy link
Copy Markdown
Contributor

@open-inspect open-inspect Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

This PR refactors the websocket sandbox integration test to wait for the init-triggered warm-up attempt before asserting the stopped/ready paths. The intent is good, but the new shared polling helper still lets the test proceed when the expected status never arrives, so the flake can remain hidden instead of failing deterministically.

PR Title and number: test: stabilize stopped sandbox websocket test (#585)
Author: @ColeMurray
Files changed: 1
Additions/deletions: +19 / -10

Critical Issues

  • [Functionality & Correctness] packages/control-plane/test/integration/websocket-sandbox.test.ts:17 - waitForSandboxStatus() exits silently on timeout. If CI is slow and the warm-up has not yet transitioned to failed within 3s, the stopped-sandbox test still continues and can race with the in-flight warm-up, which is the exact flake this PR is trying to remove. Please fail explicitly after the polling loop (for example by throwing with the last observed status) so unmet preconditions are surfaced deterministically.

Suggestions

  • [Code Quality & Readability] packages/control-plane/test/integration/websocket-sandbox.test.ts:7 - Once the helper throws on timeout, consider including the target status and last observed status in the error message to make future CI failures easier to diagnose.

Nitpicks

  • None.

Positive Feedback

  • The extraction of the polling logic removes duplication between the stopped and ready websocket tests.
  • Waiting for the init-triggered warm-up to settle is the right direction for addressing the race behind the flaky integration test.
  • The PR stays narrowly scoped to the affected test file, which keeps the intent easy to review.

Questions

  • None.

Verdict

Request Changes

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/control-plane/test/integration/websocket-sandbox.test.ts (1)

85-103: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace the fixed 100ms sleep with the same status poll.

The new helper is the right primitive here, but the post-accept() setTimeout(100) still leaves a timing window on slower CI workers. Poll for "ready" instead of sleeping so the test only proceeds once the DO has actually processed the connect handler.

🛠️ Proposed fix
     expect(ws).not.toBeNull();
     ws!.accept();
-
-    // Small delay to ensure DO has processed the connect handler fully
-    await new Promise((r) => setTimeout(r, 100));
+    await waitForSandboxStatus(stub, "ready");
 
     const stateRes = await stub.fetch("http://internal/internal/state");
     const state = await stateRes.json<{ sandbox: { status: string } }>();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/control-plane/test/integration/websocket-sandbox.test.ts` around
lines 85 - 103, After calling ws!.accept() in the "sandbox connect sets status
to ready" test, remove the fixed sleep (the setTimeout(100) promise) and instead
poll for the sandbox to reach the "ready" status using the existing helper: call
await waitForSandboxStatus(stub, "ready") so the test waits deterministically
for the DO connect handler to complete; keep the rest of the test
(initNamedSession, seedSandboxAuth, openSandboxWs, ws!.accept()) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/control-plane/test/integration/websocket-sandbox.test.ts`:
- Around line 7-18: Hoist the default timeout into a single named constant
(e.g., DEFAULT_WAIT_FOR_SANDBOX_MS) and use it as the default value for
waitForSandboxStatus(timeoutMs = DEFAULT_WAIT_FOR_SANDBOX_MS); inside
waitForSandboxStatus (which takes stub: DurableObjectStub and uses queryDO<{
status: string }>(stub, "SELECT status FROM sandbox")), when the loop exits
without seeing the expected status throw an Error that includes the expected
status and the timeout so the test will fail instead of silently continuing.

---

Outside diff comments:
In `@packages/control-plane/test/integration/websocket-sandbox.test.ts`:
- Around line 85-103: After calling ws!.accept() in the "sandbox connect sets
status to ready" test, remove the fixed sleep (the setTimeout(100) promise) and
instead poll for the sandbox to reach the "ready" status using the existing
helper: call await waitForSandboxStatus(stub, "ready") so the test waits
deterministically for the DO connect handler to complete; keep the rest of the
test (initNamedSession, seedSandboxAuth, openSandboxWs, ws!.accept()) unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b7a8cce9-d0db-47b2-9907-65497104eccb

📥 Commits

Reviewing files that changed from the base of the PR and between ad7f4ea and bf67d42.

📒 Files selected for processing (1)
  • packages/control-plane/test/integration/websocket-sandbox.test.ts

Comment thread packages/control-plane/test/integration/websocket-sandbox.test.ts
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 2, 2026

Terraform Validation Results

Step Status
Format
Init
Validate

Note: Terraform plan was skipped because secrets are not configured. This is expected for external contributors. See docs/GETTING_STARTED.md for setup instructions.

Pushed by: @open-inspect[bot], Action: pull_request

@ColeMurray ColeMurray merged commit cd68977 into main May 2, 2026
18 checks passed
@ColeMurray ColeMurray deleted the fix/websocket-sandbox-stopped-flake branch May 2, 2026 18:41
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