proto: freeze the wire contract at 1.0.0
Schemas for the whole v1 surface: 38 methods, 9 events, 25 named types and the
JSON-RPC envelope, with x-privileged / x-transports / x-deadlineMs / x-errors
annotations that both generators emit as data rather than prose.
Four generators over one IR (contracts/codegen/schema_ir.py), so the C++ structs,
the TypeScript types and the OpenRPC document cannot disagree about what the
contract says:
gen_cpp.py -> core/generated/velox_proto.{hpp,cpp}
gen_ts.py -> extension/src/shared/protocol/
gen_openrpc.py -> contracts/openrpc.json
gen_cpp_conformance.py -> tests/conformance/cpp/fixture_dispatcher.hpp
Inbound parsing never throws: parse<T>() returns std::expected<T, ParseError> and
nlohmann's throwing ADL from_json is deliberately not emitted. Schema constraints
(minimum, maxLength, pattern, ...) become real runtime checks in both languages —
the daemon does not trust the extension and the extension does not trust the
daemon.
59 golden fixtures: a success case per method, 12 error cases, 9 events. Replayed
by tests/conformance/ against both the generated C++ and a live server over both
transports. tools/mockd serves the same fixtures with unhappy-path flags so the
GUI and EXT lanes never wait for veloxd.
run.sh also proves capture.offer fails open: with a daemon answering slower than
750 ms the client gives up and lets Firefox take the download.
core/generated/ is libveloxproto, a separate target from libveloxcore, which
still never sees JSON — see docs/adr/0009.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_012fgjnqFCS5h5L7gZTZo3rV
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Emit tests/conformance/cpp/fixture_dispatcher.hpp.
|
||||
|
||||
velox::proto::Dispatcher has one pure virtual per method, on purpose: a daemon that
|
||||
forgets to implement a method does not compile. That is exactly what a conformance runner
|
||||
needs, and also what makes one tedious to hand-write — so it is generated.
|
||||
|
||||
The dispatcher answers each method from that method's golden fixture, which lets the C++
|
||||
side exercise the real dispatch path: envelope handling, the transport check, parameter
|
||||
parsing, and result serialisation.
|
||||
|
||||
Run: python3 contracts/codegen/gen_cpp_conformance.py
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
|
||||
from gen_cpp import BANNER, cpp_type, handler_name # noqa: E402
|
||||
from schema_ir import load # noqa: E402
|
||||
|
||||
OUT = Path(__file__).resolve().parent.parent.parent / "tests" / "conformance" / "cpp" / "fixture_dispatcher.hpp"
|
||||
|
||||
|
||||
def main() -> int:
|
||||
c = load()
|
||||
o = [BANNER.format(version=c.version), "#pragma once", "",
|
||||
'#include "velox_proto.hpp"', "",
|
||||
"#include <functional>", "#include <string>", "", "namespace velox::conformance {", "",
|
||||
"/// Answers every method from its golden fixture, so the generated dispatch path",
|
||||
"/// itself is under test: envelope, transport check, param parse, result serialise.",
|
||||
"class FixtureDispatcher final : public proto::Dispatcher {",
|
||||
"public:",
|
||||
" /// `results` maps a method name to that method's golden result JSON.",
|
||||
" explicit FixtureDispatcher(std::function<const nlohmann::json*(const std::string&)> results)",
|
||||
" : results_(std::move(results)) {}",
|
||||
""]
|
||||
|
||||
for m in c.methods:
|
||||
# Every method's params and result is a named struct, and this class lives in
|
||||
# velox::conformance, so the names need qualifying.
|
||||
pt, rt = "proto::" + cpp_type(m.params), "proto::" + cpp_type(m.result)
|
||||
o += [
|
||||
f" proto::Result<{rt}> {handler_name(m.name)}(const {pt}& params) override {{",
|
||||
" (void)params;",
|
||||
f' return golden<{rt}>("{m.name}");',
|
||||
" }",
|
||||
"",
|
||||
]
|
||||
|
||||
o += [
|
||||
"private:",
|
||||
" template <class T>",
|
||||
" proto::Result<T> golden(const std::string& method) {",
|
||||
" const nlohmann::json* value = results_(method);",
|
||||
" if (value == nullptr)",
|
||||
' return std::unexpected(proto::ParseError{method, "no fixture for this method"});',
|
||||
" return proto::parse<T>(*value, method);",
|
||||
" }",
|
||||
"",
|
||||
" std::function<const nlohmann::json*(const std::string&)> results_;",
|
||||
"};",
|
||||
"",
|
||||
"} // namespace velox::conformance",
|
||||
"",
|
||||
]
|
||||
OUT.parent.mkdir(parents=True, exist_ok=True)
|
||||
OUT.write_text("\n".join(o))
|
||||
print(f"gen_cpp_conformance: {len(c.methods)} handlers -> {OUT}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user