Skip to content

test: nested object literal must not corrupt an adjacent native (WS) handle - #5701

Merged
proggeramlug merged 1 commit into
PerryTS:mainfrom
machineloop:test/nested-object-literal-ws-inbound
Jun 27, 2026
Merged

test: nested object literal must not corrupt an adjacent native (WS) handle#5701
proggeramlug merged 1 commit into
PerryTS:mainfrom
machineloop:test/nested-object-literal-ws-inbound

Conversation

@machineloop

@machineloop machineloop commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a regression test for a codegen bug — present on v0.5.1206, fixed since — where a deeply nested object/array literal at module scope corrupted an adjacent native handle: it silently broke node:http WebSocket inbound dispatch globally (the upgrade handler's wsId.on("message", …) stopped firing) while outbound wsId.send(...) kept working. The literal itself read back correctly — the corruption hit a neighbouring allocation (the WS client handle), so the only observable was the dropped inbound frame. A flat, single-level literal was unaffected.

Changes

  • crates/perry/tests/nested_object_literal_ws_inbound.rs: a self-testing compile+run regression test, modeled on the existing issue_5174_headers_http_pump_hang.rs. The fixture defines a nested literal of the shape { a: [..], b: [{ kind, child: { a: [..], b: [{ kind }] } }] }, stands up a node:http WS echo server, connects a ws client to it in-process, and asserts the pingecho:ping round-trip. A healthy build prints WSOK and exits 0; a miscompile drops the inbound frame and hangs — caught by both the Rust wall-clock timeout and the fixture's own 8s exit(1).

Related issue

n/a — standalone regression guard (the underlying bug is already fixed on main).

Test plan

Verified the fixture compiles and completes the WS round-trip on a current main build:

$ perry run nested_literal_ws.ts
...
Running ...
WSOK          # exit 0
  • cargo build --release clean (-p perry, off main)
  • cargo test --workspace … — the new #[test] follows the established issue_5174 compile+run+timeout pattern; I verified the fixture's behavior directly (above) but left the full workspace test run to CI
  • (user-facing) Added a #[test] in the affected crate (crates/perry/tests/)
  • (no CLI / stdlib / runtime API changed — docs n/a)
  • (no platform UI backend touched)

Screenshots / output

Fixture stdout on a healthy build:

WSOK

Checklist

  • I have NOT bumped the workspace version or edited CLAUDE.md / CHANGELOG.md (maintainer handles these at merge)
  • My commit follows the loose feat: / fix: / docs: / chore: prefix convention (test:)
  • I've read CONTRIBUTING.md and agree to the Code of Conduct

Summary by CodeRabbit

  • Tests
    • Added a regression test covering WebSocket inbound message handling with deeply nested object and array literals.
    • Ensures the compiled app echoes received messages correctly and fails safely if execution hangs, using a timeout watchdog.

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 49b9aa5f-e8cd-4bd5-9068-16020d593dd0

📥 Commits

Reviewing files that changed from the base of the PR and between 78f02a1 and 3e7bbc1.

📒 Files selected for processing (1)
  • crates/perry/tests/nested_object_literal_ws_inbound.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/perry/tests/nested_object_literal_ws_inbound.rs

📝 Walkthrough

Walkthrough

Adds a Rust regression test that compiles an inline TypeScript WebSocket echo program, runs the resulting binary with a timeout watchdog, and asserts the echoed output.

Changes

Nested WebSocket inbound regression test

Layer / File(s) Summary
Test setup and compile helper
crates/perry/tests/nested_object_literal_ws_inbound.rs
Adds the regression-test comment and helper functions for locating perry, writing inline TypeScript into a temp directory, and compiling it to a binary.
Timeout runner
crates/perry/tests/nested_object_literal_ws_inbound.rs
Adds a watchdog runner that spawns the compiled binary, captures stdout and stderr, polls for exit, and kills the child on timeout with diagnostic output.
WS echo regression test
crates/perry/tests/nested_object_literal_ws_inbound.rs
Adds the test that compiles the nested-literal WebSocket fixture, runs it through the timeout harness, and asserts the echoed stdout.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • PerryTS/perry#5534: Touches the HTTP upgrade/WebSocket path that this regression test exercises end to end.

Poem

A bunny hopped through braces deep,
And woke the WebSocket from its sleep.
ping went in, echo came back,
WSOK lit up the rabbit track. 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is specific and accurately summarizes the regression test added for nested object literal and WebSocket handle corruption.
Description check ✅ Passed The description follows the template well, covering summary, changes, related issue, test plan, output, and checklist.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/perry/tests/nested_object_literal_ws_inbound.rs`:
- Around line 123-127: The success path in the inbound WebSocket test relies on
`ws.close()` and `server.close()` to naturally drain the event loop, which can
stall after `WSOK` is logged. Update the cleanup in the `message` handler to
make completion deterministic by explicitly finishing the test once the expected
`"echo:ping"` message is received, using the existing `timer`, `ws`, and
`server` cleanup path without depending on asynchronous close completion.
- Around line 55-57: The test fixture in nested_object_literal_ws_inbound.rs is
discarding stderr from the spawned Command, which hides the fixture’s own
failure message on both error and timeout paths. Update the child process setup
for Command::new(bin) so stderr is captured instead of sent to Stdio::null(),
and then read or surface that stderr in the test flow that uses child so
failures remain diagnosable.
🪄 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 Plus

Run ID: 502030e8-e8f7-4ad2-bfce-6401d8532914

📥 Commits

Reviewing files that changed from the base of the PR and between 240f131 and de5f5f9.

📒 Files selected for processing (1)
  • crates/perry/tests/nested_object_literal_ws_inbound.rs

Comment thread crates/perry/tests/nested_object_literal_ws_inbound.rs Outdated
Comment thread crates/perry/tests/nested_object_literal_ws_inbound.rs Outdated
@machineloop
machineloop force-pushed the test/nested-object-literal-ws-inbound branch from de5f5f9 to 78f02a1 Compare June 26, 2026 12:59
@machineloop

Copy link
Copy Markdown
Contributor Author

Addressed the two review comments:

  • Capture stderrrun_with_timeout now pipes the fixture's stderr and includes it in both the non-zero-exit assertion and the timeout panic, so the fixture's own failure signal (console.error("no echo …")) is visible on CI failures.
  • Deterministic exit — the fixture now process.exit(0)s once it receives echo:ping instead of relying on ws.close()/server.close() to drain the loop (confirmed console.log flushes before exit).

Also ran cargo fmt to clear the lint failure (the multi-line assert!/assert_eq! weren't rustfmt-clean). Re-verified the fixture round-trips 3/3 against a clean main build (WSOK, exit 0).

The security-audit failure looks unrelated — it's a cargo audit advisory in the dependency tree, and this PR adds only a test file (no dependency changes), so it should reproduce on main.

…handle

Regression guard for a codegen bug present in v0.5.1206: a deeply nested
object/array literal at module scope -- {a:[..],b:[{kind,child:{a:[..],
b:[{kind}]}}]}, an object whose array element holds a nested object that itself
holds an array of objects -- silently broke node:http WebSocket INBOUND
dispatch globally: the upgrade handler's wsId.on("message") never fired while
outbound wsId.send(...) still worked. The literal read back fine; the
corruption hit a neighbouring allocation (the WS client handle). A flat,
single-level literal was unaffected. Fixed after v0.5.1206; this test guards
the regression.

The fixture self-tests in-process: a WS echo server + a ws client that sends
"ping" and expects "echo:ping". A miscompile -> no echo -> hang; a healthy
build -> prints WSOK and exits 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@machineloop
machineloop force-pushed the test/nested-object-literal-ws-inbound branch from 781b910 to 3e7bbc1 Compare June 27, 2026 02:12
@proggeramlug
proggeramlug merged commit 19b0ba8 into PerryTS:main Jun 27, 2026
15 checks passed
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.

2 participants