Skip to content

test: e2e suite against the compiled binary - #3

Merged
WiktorStarczewski merged 3 commits into
mainfrom
test/e2e
Apr 24, 2026
Merged

WiktorStarczewski merged 3 commits into
mainfrom
test/e2e

Conversation

@WiktorStarczewski

Copy link
Copy Markdown
Owner

Summary

  • New e2e/ package with a TestMain that builds the hearsay binary once; each test spins up a subprocess with isolated HOME + scratch ~/.claude/projects/ tree and drives it over real HTTP.
  • Covers cross-process paths the in-package unit tests don't reach:
    • MCP streamable-HTTP handshake end-to-end
    • get_peer_info / list_sessions / read_session over the wire, via real mcp.StreamableClientTransport
    • Bearer-token rejection (missing / wrong scheme / wrong token)
    • hearsay invite URI matches the on-disk token
    • claude-md install/uninstall round-trip via the binary
    • hearsay pair shells out correctly — stubbed claude on PATH captures argv; we assert the claude mcp add invocation shape

Why

Existing unit tests hit ~94% via in-process transports and mocked helpers. E2E proves the process boundary (CLI parsing, on-disk config generation, HTTP listener, signal handling, real MCP transport) actually assembles.

Test plan

  • go test ./e2e/ passes locally on macOS (~1.7s for 5 tests)
  • Aggregate coverage unchanged at 93.5%
  • CI green on Ubuntu

Wiktor Starczewski added 3 commits April 24, 2026 14:29
New e2e/ package. TestMain builds the hearsay binary into a temp dir
once per test run; each test then starts a subprocess with an isolated
HOME + scratch ~/.claude/projects/ tree and drives it over real HTTP.

Covers the cross-process paths the in-package unit tests don't reach:

  * MCP streamable-HTTP handshake end-to-end
  * get_peer_info / list_sessions / read_session over the wire,
    via real mcp.StreamableClientTransport
  * Bearer-token auth rejection (missing / wrong scheme / wrong token)
  * 'hearsay invite' URI generation matches the on-disk token
  * claude-md install/uninstall round-trip via the compiled binary
  * 'hearsay pair' shells out to a stubbed `claude` on PATH; we
    capture the argv and assert the shape of the 'claude mcp add'
    invocation

Runs as part of 'go test ./...' — no new CI steps needed; existing
coverage gate is unaffected (e2e package has no production statements
to drive the aggregate number).
The .gitignore line 'hearsay' (no leading slash) was matching every
path component named 'hearsay' — including the cmd/hearsay/ source
directory. As a result cmd/hearsay/main.go and cmd/hearsay/main_test.go
were never committed to the repo despite existing on my working copy
for weeks. CI didn't catch it because:

  - go build ./... and go test ./... silently skip packages whose
    directories contain no .go files (from git's perspective, cmd/
    on main is empty).
  - The internal/ unit tests ran fine without the binary.

Adding the long-missing files and anchoring the gitignore rule to the
repo root (/hearsay) so only the compiled artifact at the root is
ignored. Now CI will actually build+test the hearsay binary itself.
The test passed 'nil' as the signal channel, assuming config.Resolve
would error out before the signal wait. On the GitHub Actions runner
that assumption didn't hold — something in the environment let
config.Resolve succeed (likely a pre-populated XDG_CONFIG_HOME), the
HTTP server booted for real, and <-nil blocks forever.

Defensive fix:
  * clear XDG_CONFIG_HOME so Dir() resolves strictly under the
    scratch HOME
  * pre-signal the channel so the server shuts down even if Resolve
    regresses in the future
  * bind to an ephemeral port so parallel tests don't collide on :3456
@WiktorStarczewski
WiktorStarczewski merged commit 8f093cc into main Apr 24, 2026
2 checks passed
@WiktorStarczewski
WiktorStarczewski deleted the test/e2e branch April 24, 2026 12:46
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