Skip to content

fix(backend): stop cross-file test-isolation leaks (MOCK_MODE + wifi timer)#157

Merged
andrescera merged 1 commit into
mainfrom
fix/mock-env-wifi-timer-isolation
Jul 17, 2026
Merged

fix(backend): stop cross-file test-isolation leaks (MOCK_MODE + wifi timer)#157
andrescera merged 1 commit into
mainfrom
fix/mock-env-wifi-timer-isolation

Conversation

@andrescera

Copy link
Copy Markdown
Member

What

Fixes two pre-existing, latent test-isolation leaks that only surface in a
full bun run --filter backend test run under a local file-execution order
that differs from CI. On the affected ordering the suite reports 1921 pass /
9 fail
; CI (a different readdir order) is green on the same commit. With this
change the full suite is 1930 pass / 0 fail in every order.

The 9 failures were: 8 in kiosk-rpc.test.ts and 1 in
wifi.procedure.test.ts. They trace to two independent leaked-state sources.

Why

bun test runs every file in ONE shared global object, so any file that leaves
process.env, a module singleton, or a pending timer dirty poisons every file
that runs after it.

Leak 1 — mock-feedback-broadcast.test.ts leaks MOCK_MODE (8 kiosk failures).
Two beforeAll blocks set process.env.MOCK_MODE = "true" and never restored
it. MOCK_MODE=true makes isDevelopment() true; combined with a leaked
mockState.initialized, shouldUseMocks() becomes true for later files. The
kiosk RPC procedures (system.procedure.ts) then take the mock branch —
resolveActiveKioskDeps() returns the in-memory mock harness instead of each
test's injected spy deps, and the !shouldUseMocks() && !isRealDevice() gate is
bypassed. So the "emulated" tests wrongly succeed, the "real" tests run against
the wrong deps (empty spies), and the "waits for cog-display" test times out.

Leak 2 — rpc-network.procedure.test.ts leaks a wifi-scan timer (1 wifi failure).
Its network.configure block calls updateNetif() in mock mode. The mock
ifconfig lists wlan0, so processIfconfigOutput schedules a detached
setTimeout(wifiUpdateDevices, 1000). That timer fires ~1s later — inside a
following mock-mode suite — and registers the mock adapter dc:a6:32:12:34:57
(id 0) into the process-wide wifiInterfacesByMacAddress registry. In
wifi.procedure.test.ts, macForDeviceId("0") then resolves to that leaked
adapter instead of the test's own seeded interface, so the held device lock is
missed and the handler returns success instead of DEVICE_BUSY.

How

  • mock-feedback-broadcast.test.ts: snapshot MOCK_MODE once and restore it in
    both teardowns — the same save/restore idiom already used by PR fix(test): restore MOCK_MODE so mock suites do not leak dev mode across the bun suite #153 for the
    mmcli-mode-validation / modem-migration leaks.
  • rpc-network.procedure.test.ts: in the network.configure afterAll, drain
    the pending wifiUpdateDevices timer (while mocks are still on) and evict the
    registered adapter before restoring the environment, so nothing leaks past the
    file.

No production code changed. No test weakened, skipped, or deleted.

How to verify

bun run --filter backend test    # 1930 pass / 0 fail

Run it a few times — the failures were deterministic per file order, so a green
result across runs is the proof. The 8 kiosk + 1 wifi cases all pass; nothing
else changes.

Risks

Low — test-only. The wifi fix adds a bounded (~1s) drain to one afterAll; it
polls for the adapter and exits as soon as it appears, then removes it. If the
timer never fires the loop is capped at 2s and the subsequent removeWifiInterface
is a harmless no-op.

…timer)

Two pre-existing latent leaks surfaced only in a full backend-suite run
under a local file ordering that differs from CI:

- mock-feedback-broadcast.test.ts set process.env.MOCK_MODE="true" in two
  beforeAll blocks and never restored it. bun runs every test file in one
  shared global, so the leaked MOCK_MODE flipped isDevelopment() true for
  later files; combined with a leaked mockState.initialized that made
  shouldUseMocks() true, the kiosk RPC procedures ran against the mock
  harness instead of each test's injected deps (8 kiosk-rpc failures).

- rpc-network.procedure.test.ts calls updateNetif() in mock mode; the mock
  ifconfig lists wlan0, so it schedules a detached setTimeout(
  wifiUpdateDevices, 1000) that fired ~1s later inside a following mock
  suite and registered the mock adapter dc:a6:32:12:34:57 (id 0) into the
  process-wide wifi-interface registry. macForDeviceId("0") then resolved
  to that leaked adapter instead of the seeded one, so the held device lock
  was missed and DEVICE_BUSY was not returned (1 wifi.procedure failure).

Restore MOCK_MODE in both teardowns (the #153 save/restore idiom) and drain
+ evict the pending wifi timer in the network.configure afterAll. Full
backend suite: 1930 pass / 0 fail, matching CI.
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: bff18f28-07fc-451b-8d3a-f9b8605a6767

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/mock-env-wifi-timer-isolation

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

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

@andrescera
andrescera merged commit ad4aca0 into main Jul 17, 2026
12 checks passed
@andrescera
andrescera deleted the fix/mock-env-wifi-timer-isolation branch July 17, 2026 01:48
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