Skip to content

test(backends): add unit tests for OpenCode stream event handling#1051

Merged
aaight merged 1 commit intodevfrom
feature/opencode-stream-unit-tests
Mar 25, 2026
Merged

test(backends): add unit tests for OpenCode stream event handling#1051
aaight merged 1 commit intodevfrom
feature/opencode-stream-unit-tests

Conversation

@aaight
Copy link
Copy Markdown
Collaborator

@aaight aaight commented Mar 25, 2026

Summary

  • Adds tests/unit/backends/opencode-stream.test.ts with 53 unit tests covering all stream event helper functions in src/backends/opencode/stream.ts
  • Tests cover appendPartialOutput, getPartialOutput, reportToolPart, handleSessionTerminalEvent, handleMessagePartUpdated, and handlePermissionEvent
  • Follows the existing mock patterns from opencode.test.ts and opencode-permissions.test.ts

What was tested

  • appendPartialOutput / getPartialOutput: text trimming, empty/whitespace rejection, chunk accumulation and joining
  • reportToolPart: deduplication via reportedToolCalls Set, pending-state skip, distinct call tracking
  • handleSessionTerminalEvent: session.error (with/without sessionID, error message extraction, fallback to name), session.idle (sessionID match/mismatch), session.status idle detection
  • handleMessagePartUpdated: session-ID mismatch guard, step-start iteration counting, step-finish cost accumulation and LLM call logging, tool-call deduplication, text delta streaming, non-streaming text deduplication, synthetic/ignored part skipping, logWriter truncation at 300 chars
  • handlePermissionEvent: session-ID mismatch returns false, allow/deny decision routing through resolvePermissionDecision + normalizePermissionDecision, SDK client called with correct path/body shape

Technical notes

  • Mocked @opencode-ai/sdk/client, node:fs, runsRepository, nativeToolRetry, and logging at the module boundary — no full engine orchestration
  • nativeToolRetry is mocked as a pass-through to avoid timer complexity
  • clearMocks: true in global vitest config requires a beforeEach resetting mockStoreLlmCall to mockResolvedValue(undefined) in the step-finish suite so logLlmCall's .catch() does not throw

Trello card

https://trello.com/c/69c3e0fc5b8788ac3c9fe573

🤖 Generated with Claude Code

🕵️ claude-code · claude-sonnet-4-6 · run details

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 25, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Collaborator

@nhopeatall nhopeatall left a comment

Choose a reason for hiding this comment

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

Summary

LGTM — Well-structured unit tests that accurately cover the exported stream event handling helpers.

I traced each test suite against the source implementation in src/backends/opencode/stream.ts and verified:

  • Mock strategy is correct: Mocks are applied at the leaf dependency boundary (runsRepository, node:fs, logging, nativeToolRetry) rather than at intermediate modules, which means the real logLlmCall and appendEngineLog logic is exercised through their actual code paths.
  • Session ID matching logic is properly tested: The casing asymmetry (sessionID in events vs sessionId in state) matches the source and is consistently used across all test suites.
  • Text deduplication logic is accurately verified: The tests correctly distinguish between streaming (delta-based, no dedup) and non-streaming (part.id-based dedup) paths through getPartDelta + the seenTextPartIds guard.
  • Permission normalization chain is tested end-to-end: resolvePermissionDecision → normalizePermissionDecision mapping ('allow' → 'always', 'deny' → 'reject') is verified for each permission type.
  • Fire-and-forget logLlmCall is handled correctly: The mockStoreLlmCall.mockResolvedValue(undefined) reset in beforeEach prevents the .catch() chain in logLlmCall from throwing after clearMocks resets return values — the PR description explains this well.
  • retryNativeToolOperation pass-through mock is an appropriate simplification that avoids timer complexity while still exercising the actual permission response path.

53 tests covering all 6 exported functions with good edge case coverage (whitespace, undefined state, synthetic/ignored parts, session mismatches, deduplication). All CI checks pass.

🕵️ claude-code · claude-opus-4-6 · run details

@aaight aaight merged commit 0006c46 into dev Mar 25, 2026
9 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