fix(test): prevent memory and resource leaks in test infrastructure #6630

Open
opened 2026-02-16 18:04:48 -05:00 by yindo · 1 comment
Owner

Originally created by @wvanderen on GitHub (Jan 17, 2026).

Originally assigned to: @rekram1-node on GitHub.

GitHub Issue Draft


Title: `fix(test): prevent memory and resource leaks in test infrastructure

Type: bug

Labels: bug, perf, test, infrastructure


Description

Critical resource leaks in test infrastructure causing disk/memory bloat and OOM crashes during development.

When running tests (bun test or bun test --watch), the test framework accumulates resources without cleanup, leading to:

  • Temporary directories never being deleted
  • Spawned processes leaking on test failures
  • Eventually triggering OOM killer (vitest workers consuming ~900MB each)
  • Terminals closing unexpectedly (appears as "freezes" to developers)

This affects anyone running tests locally, especially in watch mode.


Evidence

System Logs (journalctl)

Jan 17 13:14 - vitest worker memory usage:
• vitest 1: 897 MB
• vitest 2: 900 MB
• vitest 3: 910 MB
• vitest 4: 905 MB
• vitest 5: 898 MB
• vitest 7: 912 MB

Total: ~5.3 GB for test workers alone!

OOM Killer Activity

Jan 17 13:14:28 lemarchy kernel: Out of memory: Killed process 1750015 (node (vitest 7))
  total-vm:4985788kB, anon-rss:3646756kB, file-rss:620kB

Jan 17 11:52:14 lemarchy kernel: Out of memory: Killed process 1627971 (node (vitest 3))
  total-vm:3727456kB, anon-rss:2268820kB

V8 stack trace shows:
  V8::FatalProcessOutOfMemory
  → Node aborts (signal 6/ABRT)
  → Terminal closes

System State

  • Swap: 3.9 GB / 4 GB used (95% full)
  • Workers: 6-11 vitest workers spawned per run
  • Impact: System becomes sluggish, eventually unresponsive

Root Causes

1. Temp Directory Cleanup Disabled

File: packages/opencode/test/fixture/fixture.ts

const result = {
  [Symbol.asyncDispose]: async () => {
    await options?.dispose?.(dirpath)
    // await fs.rm(dirpath, { recursive: true, force: true })  // ❌ COMMENTED OUT
  },
  path: realpath,
  extra: extra as T,
}

Every tmpdir() fixture call creates a permanent directory that is never deleted.


2. Process Leaks in LSP Tests

File: packages/opencode/test/lsp/client.test.ts

test("handles workspace/workspaceFolders request", async () => {
  const handle = spawnFakeServer() as any

  const client = await Instance.provide({...})  // ❌ If this throws, handle leaks

  await client.shutdown()  // Never reached if above throws
})

Fake LSP server processes are spawned for each test but only cleaned up if test completes successfully.


Impact

  • Developers: Test runs consume increasing amounts of memory/disk space
  • CI/CD: May experience OOM failures in test pipelines
  • System: Swap fills up, causing system-wide slowdowns
  • Experience: Terminals "freeze" then close, disrupting development workflow

Steps to Reproduce

Temp Directory Leak

  1. Run tests multiple times:
    cd packages/opencode
    bun test
    
  2. Check /tmp/ for accumulated directories:
    ls -la /tmp/ | grep opencode-test
    
  3. Observe hundreds of persistent temp directories

Process Leak

  1. Force a test to fail in packages/opencode/test/lsp/client.test.ts:
    test("handles workspace/workspaceFolders request", async () => {
      const handle = spawnFakeServer() as any
      throw new Error("Force failure to test cleanup")  // ✅ Process leaks here
    })
    
  2. Run tests: bun test
  3. Check for orphan Node.js processes:
    ps aux | grep fake-lsp-server
    
  4. Observe processes remain after test completes

Expected Behavior

  1. Temp directories: Should be deleted when test fixtures are disposed
  2. Processes: Should always be cleaned up, even on test failures
  3. Memory: Should remain stable across test runs in watch mode

Actual Behavior

  1. Temp directories: Accumulate in /tmp/ directory forever
  2. Processes: Leak when tests fail before cleanup
  3. Memory: Grows until OOM killer terminates tests

Related Issues

  • #7261 - "v1.1.6 still has memory bloat - heap not released + MCP orphan processes"

    • Similar pattern of resource leaks (MCP servers not terminated)
    • Our fix addresses test infrastructure specifically
  • #8899 / #8898 - "test: tests fail for developers with global git hooks"

    • Also touches test/fixture/fixture.ts
    • Shows test infrastructure needing isolation improvements

Proposed Fix

See PR: fix(test): prevent memory and resource leaks

Changes

  1. Re-enable temp directory cleanup in tmpdir() fixture
  2. Add try/finally blocks to LSP client tests ensuring process cleanup
  3. Processes now killed even when tests throw exceptions

Files Changed

  • packages/opencode/test/fixture/fixture.ts - Uncomment cleanup line
  • packages/opencode/test/lsp/client.test.ts - Add try/finally blocks

Testing Verification

After applying fix, verify:

# 1. Temp directories are cleaned up
cd packages/opencode
bun test --run
ls -la /tmp/ | grep opencode-test  # Should show empty or minimal results

# 2. No orphan processes after test failures
# Force a test to fail temporarily, then:
ps aux | grep fake-lsp-server  # Should show no processes

# 3. Memory stable in watch mode
watch -n 5 'ps aux | grep "vitest\|bun test" | awk "{sum += \$6} END {print "Total RSS:", sum/1024, "MB"}'
# Should remain stable (not grow indefinitely)

Workaround (Until PR Merged)

For developers experiencing this issue now:

# Add to shell config (~/.zshrc or ~/.bashrc)
export BUN_MAX_THREADS=2

# Disable coverage for development (edit bunfig.toml)
# coverage = false

# Clean up accumulated temp directories manually
rm -rf /tmp/opencode-test-*

OpenCode Version

v1.1.24 (current dev branch)


Environment

  • OS: Arch Linux 6.18.3-arch1-1
  • Terminal: Alacritty
  • Node: v25.2.1
  • RAM: 30 GB (Swap: 4 GB, 95% full during test runs)

Additional Notes

This is a first-time contribution. Happy to make any adjustments to the fix or documentation.

Process leaks in LSP tests are a common pattern - any test spawning subprocesses should use try/finally or afterEach hooks for guaranteed cleanup.

Originally created by @wvanderen on GitHub (Jan 17, 2026). Originally assigned to: @rekram1-node on GitHub. # GitHub Issue Draft --- **Title:** `fix(test): prevent memory and resource leaks in test infrastructure **Type:** bug **Labels:** bug, perf, test, infrastructure --- ## Description Critical resource leaks in test infrastructure causing disk/memory bloat and OOM crashes during development. When running tests (`bun test` or `bun test --watch`), the test framework accumulates resources without cleanup, leading to: - Temporary directories never being deleted - Spawned processes leaking on test failures - Eventually triggering OOM killer (vitest workers consuming ~900MB each) - Terminals closing unexpectedly (appears as "freezes" to developers) This affects anyone running tests locally, especially in watch mode. --- ## Evidence ### System Logs (journalctl) ``` Jan 17 13:14 - vitest worker memory usage: • vitest 1: 897 MB • vitest 2: 900 MB • vitest 3: 910 MB • vitest 4: 905 MB • vitest 5: 898 MB • vitest 7: 912 MB Total: ~5.3 GB for test workers alone! ``` ### OOM Killer Activity ``` Jan 17 13:14:28 lemarchy kernel: Out of memory: Killed process 1750015 (node (vitest 7)) total-vm:4985788kB, anon-rss:3646756kB, file-rss:620kB Jan 17 11:52:14 lemarchy kernel: Out of memory: Killed process 1627971 (node (vitest 3)) total-vm:3727456kB, anon-rss:2268820kB V8 stack trace shows: V8::FatalProcessOutOfMemory → Node aborts (signal 6/ABRT) → Terminal closes ``` ### System State - **Swap:** 3.9 GB / 4 GB used (95% full) - **Workers:** 6-11 vitest workers spawned per run - **Impact:** System becomes sluggish, eventually unresponsive --- ## Root Causes ### 1. Temp Directory Cleanup Disabled **File:** `packages/opencode/test/fixture/fixture.ts` ```typescript const result = { [Symbol.asyncDispose]: async () => { await options?.dispose?.(dirpath) // await fs.rm(dirpath, { recursive: true, force: true }) // ❌ COMMENTED OUT }, path: realpath, extra: extra as T, } ``` Every `tmpdir()` fixture call creates a permanent directory that is never deleted. --- ### 2. Process Leaks in LSP Tests **File:** `packages/opencode/test/lsp/client.test.ts` ```typescript test("handles workspace/workspaceFolders request", async () => { const handle = spawnFakeServer() as any const client = await Instance.provide({...}) // ❌ If this throws, handle leaks await client.shutdown() // Never reached if above throws }) ``` Fake LSP server processes are spawned for each test but only cleaned up if test completes successfully. --- ## Impact - **Developers:** Test runs consume increasing amounts of memory/disk space - **CI/CD:** May experience OOM failures in test pipelines - **System:** Swap fills up, causing system-wide slowdowns - **Experience:** Terminals "freeze" then close, disrupting development workflow --- ## Steps to Reproduce ### Temp Directory Leak 1. Run tests multiple times: ```bash cd packages/opencode bun test ``` 2. Check `/tmp/` for accumulated directories: ```bash ls -la /tmp/ | grep opencode-test ``` 3. Observe hundreds of persistent temp directories ### Process Leak 1. Force a test to fail in `packages/opencode/test/lsp/client.test.ts`: ```typescript test("handles workspace/workspaceFolders request", async () => { const handle = spawnFakeServer() as any throw new Error("Force failure to test cleanup") // ✅ Process leaks here }) ``` 2. Run tests: `bun test` 3. Check for orphan Node.js processes: ```bash ps aux | grep fake-lsp-server ``` 4. Observe processes remain after test completes --- ## Expected Behavior 1. **Temp directories:** Should be deleted when test fixtures are disposed 2. **Processes:** Should always be cleaned up, even on test failures 3. **Memory:** Should remain stable across test runs in watch mode --- ## Actual Behavior 1. **Temp directories:** Accumulate in `/tmp/` directory forever 2. **Processes:** Leak when tests fail before cleanup 3. **Memory:** Grows until OOM killer terminates tests --- ## Related Issues - **#7261** - "v1.1.6 still has memory bloat - heap not released + MCP orphan processes" - Similar pattern of resource leaks (MCP servers not terminated) - Our fix addresses test infrastructure specifically - **#8899 / #8898** - "test: tests fail for developers with global git hooks" - Also touches `test/fixture/fixture.ts` - Shows test infrastructure needing isolation improvements --- ## Proposed Fix See PR: `fix(test): prevent memory and resource leaks` ### Changes 1. Re-enable temp directory cleanup in `tmpdir()` fixture 2. Add `try/finally` blocks to LSP client tests ensuring process cleanup 3. Processes now killed even when tests throw exceptions ### Files Changed - `packages/opencode/test/fixture/fixture.ts` - Uncomment cleanup line - `packages/opencode/test/lsp/client.test.ts` - Add try/finally blocks --- ## Testing Verification After applying fix, verify: ```bash # 1. Temp directories are cleaned up cd packages/opencode bun test --run ls -la /tmp/ | grep opencode-test # Should show empty or minimal results # 2. No orphan processes after test failures # Force a test to fail temporarily, then: ps aux | grep fake-lsp-server # Should show no processes # 3. Memory stable in watch mode watch -n 5 'ps aux | grep "vitest\|bun test" | awk "{sum += \$6} END {print "Total RSS:", sum/1024, "MB"}' # Should remain stable (not grow indefinitely) ``` --- ## Workaround (Until PR Merged) For developers experiencing this issue now: ```bash # Add to shell config (~/.zshrc or ~/.bashrc) export BUN_MAX_THREADS=2 # Disable coverage for development (edit bunfig.toml) # coverage = false # Clean up accumulated temp directories manually rm -rf /tmp/opencode-test-* ``` --- ## OpenCode Version v1.1.24 (current dev branch) --- ## Environment - **OS:** Arch Linux 6.18.3-arch1-1 - **Terminal:** Alacritty - **Node:** v25.2.1 - **RAM:** 30 GB (Swap: 4 GB, 95% full during test runs) --- ## Additional Notes This is a first-time contribution. Happy to make any adjustments to the fix or documentation. Process leaks in LSP tests are a common pattern - any test spawning subprocesses should use `try/finally` or `afterEach` hooks for guaranteed cleanup.
yindo added the perf label 2026-02-16 18:04:48 -05:00
Author
Owner

@github-actions[bot] commented on GitHub (Jan 17, 2026):

This issue might be a duplicate of existing issues. Please check:

  • #7261: v1.1.6 still has memory bloat - heap not released + MCP orphan processes (similar pattern of resource leaks affecting system stability)
  • #8899: test: tests fail for developers with global git hooks (also touches test/fixture/fixture.ts infrastructure)

Feel free to ignore if none of these address your specific case.

@github-actions[bot] commented on GitHub (Jan 17, 2026): This issue might be a duplicate of existing issues. Please check: - #7261: v1.1.6 still has memory bloat - heap not released + MCP orphan processes (similar pattern of resource leaks affecting system stability) - #8899: test: tests fail for developers with global git hooks (also touches test/fixture/fixture.ts infrastructure) Feel free to ignore if none of these address your specific case.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#6630