🐛 fix(core): return JSON-RPC protocol errors

This commit is contained in:
csh
2026-07-14 08:22:40 +08:00
parent 06a0da5124
commit efb6eae796
5 changed files with 143 additions and 16 deletions
+40
View File
@@ -14,6 +14,10 @@ def frame(message: dict) -> bytes:
return f"Content-Length: {len(body)}\r\n\r\n".encode("ascii") + body
def raw_frame(body: bytes) -> bytes:
return f"Content-Length: {len(body)}\r\n\r\n".encode("ascii") + body
def read_messages(data: bytes) -> list[dict]:
messages = []
offset = 0
@@ -169,12 +173,48 @@ def assert_lifecycle(server: Path) -> None:
client.kill()
def assert_json_rpc_errors(server: Path) -> None:
payload = b"".join([
raw_frame(b'{"jsonrpc":"2.0",'),
raw_frame(b"[]"),
raw_frame(b'{"jsonrpc":"1.0","id":7,"method":"initialize"}'),
frame({
"jsonrpc": "2.0",
"id": 8,
"method": "initialize",
"params": {},
}),
frame({"jsonrpc": "2.0", "id": 9, "method": "missing/method"}),
frame({"jsonrpc": "2.0", "id": 10, "method": "shutdown"}),
frame({"jsonrpc": "2.0", "method": "exit"}),
])
result = run_raw(server, payload)
if result.returncode != 0:
raise RuntimeError("JSON-RPC error sequence should shut down cleanly")
responses = read_messages(result.stdout)
if responses[0].get("id", "missing") is not None:
raise RuntimeError(
f"ParseError response should use a null id: {responses[0]!r}")
if responses[0].get("error", {}).get("code") != -32700:
raise RuntimeError("Malformed JSON should return ParseError")
if responses[1].get("id", "missing") is not None:
raise RuntimeError("InvalidRequest response should use a null id")
if responses[1].get("error", {}).get("code") != -32600:
raise RuntimeError("A non-object JSON value should return InvalidRequest")
if response_by_id(result.stdout, 7).get("error", {}).get("code") != -32600:
raise RuntimeError("jsonrpc other than 2.0 should return InvalidRequest")
if response_by_id(result.stdout, 9).get("error", {}).get("code") != -32601:
raise RuntimeError("Unknown request method should return MethodNotFound")
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--server", type=Path, required=True)
args = parser.parse_args()
assert_lifecycle(args.server)
assert_json_rpc_errors(args.server)
return 0