test: add opencode HTTP server integration tests + install opencode in CI#6
Merged
JohnnyVicious merged 2 commits intomainfrom Apr 12, 2026
Merged
Conversation
…n CI
Adds protocol-level integration tests for the OpenCode HTTP wrapper our
companion script is built on. These were previously untested — none of
the existing 57 unit tests touched `lib/opencode-server.mjs` because
running them requires a real `opencode serve` process. The CI workflow
now installs `opencode-ai` so these tests can run.
New file: `tests/opencode-server.test.mjs`
Spawns `opencode serve` on a high test port (default 14096, override
via `OPENCODE_TEST_PORT`) so it does not collide with a developer's
default-port server. Tears the server down via SIGTERM in `after()`,
even on test failure.
Coverage:
* `isServerRunning` detects the spawned server
* `health()` returns `{ healthy: true, version: <string> }`
* `createSession` returns an id
* `listSessions` includes a freshly-created session
* `createSession` -> `getSession` -> `deleteSession` roundtrip, with
the post-delete `getSession` rejected with a 4xx
Intentionally does NOT exercise `sendPrompt` because that would call a
configured AI provider and burn paid API credits in CI. End-to-end
review tests will need a separate workflow with secrets.
Local skipping: the entire suite is gated on `isOpencodeInstalled()`
via `describe.skip`, so developers without `opencode` on their PATH can
still run `npm test` without failures.
CI changes (`.github/workflows/ci.yml`):
* New "Install OpenCode CLI" step running `npm install -g opencode-ai`,
modeled after codex-plugin-cc's `Install Codex CLI` step.
* `timeout-minutes: 5 -> 10` to absorb the cli install + opencode server
startup overhead.
* Updated header comment to explain we install opencode (not codex).
Test count: 57 -> 62. All passing locally with `OPENCODE_TEST_PORT=14096`.
CI run 24307439945 reported the integration tests passing in 0.3s, then node:test sat idle for the full 10-minute job timeout before the runner was forced to terminate an orphan opencode process. Two bugs: 1. Latent upstream bug in `lib/opencode-server.mjs#ensureServer`. It spawned `opencode serve` with `stdio: ["ignore", "pipe", "pipe"]` but never read the piped stdout/stderr. Those pipe FDs were ref'd on the parent's event loop, so any long-lived parent (notably node:test) would deadlock once opencode's log output filled the pipe buffer. In normal CLI usage the bug was masked because the companion script exited fast enough that the OS reaped the pipes. Switching to `stdio: "ignore"` redirects opencode's output to /dev/null, removing the parent-side handles entirely. This is a real upstream fix and has no production-side downside. 2. The test cleanup in `tests/opencode-server.test.mjs#after` killed only the spawned PID, not its process group, and had no SIGKILL fallback. Since opencode is spawned with `detached: true` it lives in its own group; SIGTERM-ing the leader doesn't guarantee the whole tree exits. Now we kill `-pid` (the group), poll for graceful exit for 3s via `kill(pid, 0)`, and SIGKILL the group as a last resort. Verified locally with `time OPENCODE_TEST_PORT=14096 npm test`: ℹ tests 62 ℹ pass 62 real 0m2.034s Port 14096 is empty after the run.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds protocol-level integration tests for the OpenCode HTTP wrapper our companion script is built on. None of the existing 57 unit tests touched
lib/opencode-server.mjsbecause running them requires a realopencode serveprocess. The CI workflow now installsopencode-aiso these tests can run.What's covered
New file
tests/opencode-server.test.mjsspawnsopencode serveon a high test port (default14096, override viaOPENCODE_TEST_PORT) so it doesn't collide with a developer's default-port server. Tears the server down via SIGTERM inafter(), even on test failure.isServerRunning detects the spawned serverisServerRunning(host, port)returnstrueafterensureServerhealth() reports healthy with a version string{ healthy: true, version: "<non-empty>" }createSession returns an idlistSessions ... contains a freshly-created sessionlistSessions()includes the new idcreateSession -> getSession -> deleteSession roundtripWhat's intentionally NOT covered
client.sendPrompt/handleReview/handleAdversarialReviewend-to-end. These require a configured AI provider and would burn paid API credits in CI on every PR. Codex's CI doesn't run them either. If we want them, they need a separate workflow with secrets.Local skipping
The whole suite is gated on
isOpencodeInstalled()viadescribe.skip, so developers withoutopencodeon PATH can still runnpm testwithout failures.CI changes (
.github/workflows/ci.yml)npm install -g opencode-ai. Modeled after codex-plugin-cc'sInstall Codex CLIstep.timeout-minutes5 → 10 to absorb the CLI install + server startup overhead.Test plan
node --check tests/opencode-server.test.mjspassesOPENCODE_TEST_PORT=14096 npm test— 62 tests / 0 failures (was 57 / 0 before)14096)Out of scope
While I was sweeping
package.json, I noticed"license": "MIT"contradicts theLICENSEfile (Apache 2.0). It's an upstream bug we inherited. Worth a separate one-line fix later — not bundled here to keep this PR focused on tests + CI.