Repository navigation
test: end-to-end test with a Go-parity fixture (#9) - #26
Merged
Merged
Conversation
added 2 commits
October 10, 2026 01:48
Port Go's examples/gen/example/v1/e2e_test.go (stablekernel/protoc-gen-go-mcp @ 9e072f9) to examples/tests/e2e.rs: a fake VibeService backend runs behind a real in-process tonic server, the generated VibeServiceMcpServer sits in front of it, and the test talks MCP over an in-memory transport to drive tools/list and tools/call the same way a real MCP client would. All rmcp types stay inside the harness; the test functions work with plain ToolInfo/ ToolResult values decoded from the wire response. Ports TestToolsList, TestCallSetVibe, TestCallGetVibe, TestCallSetVibeDetails, TestCallSetVibeArray, TestCallSetVibeObjects, TestCallSetVibe_GRPCError, TestCallSetVibe_InvalidArgumentType and TestCallSetVibe_UnknownField. Adds the cross-implementation parity fixture examples/tests/parity/go-v0.3.0-tools.json: Go 0.3.0's tools/list result for example.proto, extracted from its committed example_mcp.pb.go (no Go toolchain was available to run mcp-vibe directly). Asserts the Rust server's tools/list is JSON-equal to it, and that SetVibeDetails's tools/call result text matches Go's expected output for the same input.
- Add parity/README.md documenting how the Go tools/list fixture was
captured (extracted from Go's committed example_mcp.pb.go, no Go
toolchain available), replacing doc comments that incorrectly
pointed at a 'header comment' in the JSON fixture file (JSON has no
comment syntax).
- Assert the gRPC-error tool result text exactly
('rpc error: code = NotFound desc = vibe not found'), matching the
exact-match convention already used by handler.rs and
server_integration.rs, instead of two separate .contains() checks.
- Fix a stale doc comment on new_test_harness describing a return
shape it no longer has.
3 tasks
Contributor
Author
|
🔍 Review: LGTM. I checked the fixture against a live Go server. I built Go's Two observations, neither blocking:
|
This was referenced Oct 10, 2026
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.
Closes #9
Summary
Adds
examples/tests/e2e.rs, the Rust counterpart of Go'sexamples/gen/example/v1/e2e_test.goatstablekernel/protoc-gen-go-mcpcommit9e072f9: a fakeVibeServicebackend runs behind a real in-process tonic server, the generated
VibeServiceMcpServersits in front of it, and the test talks MCP overan in-memory
tokio::io::duplextransport to drivetools/listandtools/callthe same way a real MCP client would. Everyrmcptype isconfined to the harness (
new_test_harness/list_tools/call_tool);the test functions work only with plain
ToolInfo/ToolResultvaluesdecoded from the wire response, as Go's do.
Ports all nine named Go tests:
TestToolsList→tools_list_reports_all_five_tools_with_descriptions_and_schemasTestCallSetVibe→call_set_vibe_sends_request_and_returns_backend_resultTestCallGetVibe→call_get_vibe_sends_request_and_returns_backend_resultTestCallSetVibeDetails→call_set_vibe_details_sends_request_and_returns_backend_resultTestCallSetVibeArray→call_set_vibe_array_sends_request_and_returns_backend_resultTestCallSetVibeObjects→call_set_vibe_objects_sends_request_and_returns_backend_resultTestCallSetVibe_GRPCError→call_set_vibe_grpc_error_becomes_tool_errorTestCallSetVibe_InvalidArgumentType→call_set_vibe_invalid_argument_type_never_reaches_backendTestCallSetVibe_UnknownField→call_set_vibe_unknown_field_never_reaches_backendSame inputs as Go, and the same assertions: what the fake backend
received (via a small
RecordedRequestenum keyed by RPC name, thecounterpart of Go's
fakeVibeService.lastRequest/callCount) and whatthe client got back.
Parity fixture: adds
examples/tests/parity/go-v0.3.0-tools.json,Go 0.3.0's
tools/listresult forexample.proto'sVibeService(name/description/inputSchema per tool). How it was captured: no Go
toolchain was available in this environment to
go run ./cmd/mcp-vibe, so it was extracted from Go's committedexamples/gen/example/v1/example_mcp.pb.goat9e072f9(each tool'sName,DescriptionandInputSchemaliteral, fetched fromraw.githubusercontent.comand copied verbatim) — seeexamples/tests/parity/README.mdfor the full explanation. This is thesame source
examples/tests/mcp_tool_parity.rs(issue #6) alreadydraws from; the README cross-references both so a future change to
either stays in sync.
tools_list_matches_go_v0_3_0_parity_fixtureasserts the Rustserver's real
tools/listresponse is JSON-equal to the fixture(sorted by tool name on both sides, since this generator's
BTreeMap-backed registration order differs from Go'sinsertion-ordered slice — not part of MCP's
tools/listcontract).set_vibe_details_result_matches_go_tools_call_resultassertsSetVibeDetails'stools/callresult text, for the same input asTestCallSetVibeDetails, is JSON-equal to{"previousVibe":"mellow","vibe":"groovy"}— the value Go'sprotojson.Marshalwould produce for the backend'sSetVibeResponse{PreviousVibe: "mellow", Vibe: "groovy"}(bothfields non-zero, so protojson/pbjson both include them). Derived by
reading protojson's field-presence rules rather than running Go,
for the same toolchain-availability reason as above.
Decisions made
established in
examples/tests/handler.rsandprotoc-gen-rust-mcp/tests/server_integration.rs(snake_casedescriptive test names instead of Go's
TestXxx, exact-matchassertions on gRPC error text, a
lazy_client-style never-connectsclient isn't needed here since every test in this file exercises a
real backend).
RecordedRequestenum instead ofBox<dyn Any>to keepthe "what did the backend receive" assertions type-safe, since Rust
doesn't have Go's convenient
any+ type-assert idiom.Test evidence
No changes to the generator or
example.proto, somake generatewasonly run to confirm no drift (
git statusclean after regenerating).Mutation check (acceptance criterion)
Broke one schema rule in the generator —
schema.rs's message schemabuilder, changed
additionalProperties: falsetotrue(so unknownfields would silently validate) — and reran
cargo test --workspace:protoc-gen-rust-mcp's existing unit tests caught it immediately:schema::tests::parity_with_go_example_input_schemas,schema::tests::all_scalars,schema::tests::schema_test_messageall failed (schema no longer matches the committed/expected JSON).
examples/with the mutated generator(
make generate), this issue's new end-to-end tests also caught it:tools_list_reports_all_five_tools_with_descriptions_and_schemasand
tools_list_matches_go_v0_3_0_parity_fixtureboth failed (thelive server's schema no longer matches the Go parity fixture).
Reverted the mutation and regenerated again before committing;
git statuswas clean (no generated-file drift from the real generator).Notes for reviewers
No Go toolchain was available in this sandbox to run
mcp-vibedirectly over stdio, so the fixture was captured by extraction
instead (per the issue's explicit fallback option); see
examples/tests/parity/README.md.This PR only adds test files (
examples/tests/e2e.rs,examples/tests/parity/go-v0.3.0-tools.json,examples/tests/parity/README.md); no generator or generated-codechanges.
Self-reviewed via the
reviewersubagent; addressed its twoblocking findings (a doc comment pointing at a nonexistent JSON
"header comment" — JSON has no comment syntax, now replaced with a
pointer to the new
parity/README.md— and a looser-than-conventioncontains()-based assertion on the gRPC error text, now an exactmatch) plus a stale doc comment it flagged.
Factory-authored