Skip to main content
Glama

Gemini MCP Server

by lbds137
test_json_rpc.py•11.1 kB
""" Tests for the JSON-RPC 2.0 implementation. """ import json from unittest.mock import MagicMock, patch import pytest from gemini_mcp.json_rpc import ( ERROR_INTERNAL, ERROR_INVALID_REQUEST, ERROR_METHOD_NOT_FOUND, ERROR_PARSE, JsonRpcError, JsonRpcRequest, JsonRpcResponse, JsonRpcServer, create_error_response, create_result_response, create_text_content, create_tool, ) class TestJsonRpcRequest: """Test the JsonRpcRequest class.""" def test_valid_request(self): """Test creating a valid request.""" data = {"jsonrpc": "2.0", "method": "test_method", "params": {"foo": "bar"}, "id": 1} request = JsonRpcRequest(data) assert request.jsonrpc == "2.0" assert request.method == "test_method" assert request.params == {"foo": "bar"} assert request.id == 1 def test_request_without_params(self): """Test request without params defaults to empty dict.""" data = {"jsonrpc": "2.0", "method": "test_method", "id": 1} request = JsonRpcRequest(data) assert request.params == {} def test_invalid_jsonrpc_version(self): """Test request with invalid JSON-RPC version.""" data = {"jsonrpc": "1.0", "method": "test_method", "id": 1} with pytest.raises(ValueError, match="Invalid JSON-RPC version"): JsonRpcRequest(data) def test_missing_method(self): """Test request without method.""" data = {"jsonrpc": "2.0", "id": 1} with pytest.raises(ValueError, match="Missing method"): JsonRpcRequest(data) def test_notification_without_id(self): """Test notification (request without id).""" data = {"jsonrpc": "2.0", "method": "notify"} request = JsonRpcRequest(data) assert request.id is None class TestJsonRpcResponse: """Test the JsonRpcResponse class.""" def test_success_response(self): """Test creating a success response.""" response = JsonRpcResponse(result={"data": "test"}, id=1) d = response.to_dict() assert d["jsonrpc"] == "2.0" assert d["id"] == 1 assert d["result"] == {"data": "test"} assert "error" not in d def test_error_response(self): """Test creating an error response.""" error = {"code": -32601, "message": "Method not found"} response = JsonRpcResponse(error=error, id=1) d = response.to_dict() assert d["jsonrpc"] == "2.0" assert d["id"] == 1 assert d["error"] == error assert "result" not in d def test_response_with_null_id(self): """Test response with null id (for parse errors).""" response = JsonRpcResponse(error={"code": -32700, "message": "Parse error"}, id=None) d = response.to_dict() assert d["id"] is None class TestJsonRpcError: """Test the JsonRpcError class.""" def test_error_without_data(self): """Test error without additional data.""" error = JsonRpcError(code=-32601, message="Method not found") d = error.to_dict() assert d == {"code": -32601, "message": "Method not found"} def test_error_with_data(self): """Test error with additional data.""" error = JsonRpcError(code=-32602, message="Invalid params", data={"param": "value"}) d = error.to_dict() assert d == {"code": -32602, "message": "Invalid params", "data": {"param": "value"}} class TestJsonRpcServer: """Test the JsonRpcServer class.""" def test_init(self): """Test server initialization.""" server = JsonRpcServer("test-server") assert server.server_name == "test-server" assert server._handlers == {} assert server._running is False def test_register_handler(self): """Test registering a handler.""" server = JsonRpcServer("test-server") handler = MagicMock() server.register_handler("test_method", handler) assert server._handlers["test_method"] == handler @patch("sys.stdin") def test_read_message_success(self, mock_stdin): """Test successful message reading.""" server = JsonRpcServer("test-server") mock_stdin.readline.return_value = '{"test": "data"}\n' result = server._read_message() assert result == '{"test": "data"}' @patch("sys.stdin") def test_read_message_empty(self, mock_stdin): """Test reading empty message.""" server = JsonRpcServer("test-server") mock_stdin.readline.return_value = "" result = server._read_message() assert result is None @patch("sys.stdin") def test_read_message_exception(self, mock_stdin): """Test exception during reading.""" server = JsonRpcServer("test-server") mock_stdin.readline.side_effect = Exception("Read error") result = server._read_message() assert result is None @patch("builtins.print") def test_write_message_success(self, mock_print): """Test successful message writing.""" server = JsonRpcServer("test-server") message = {"test": "data"} server._write_message(message) mock_print.assert_called_once_with('{"test": "data"}', flush=True) @patch("builtins.print") def test_write_message_exception(self, mock_print): """Test exception during writing.""" server = JsonRpcServer("test-server") mock_print.side_effect = Exception("Write error") # Should not raise, just log the error server._write_message({"test": "data"}) def test_process_request_parse_error(self): """Test processing invalid JSON.""" server = JsonRpcServer("test-server") result = server._process_request("{invalid json") assert result["error"]["code"] == ERROR_PARSE assert "Parse error" in result["error"]["message"] def test_process_request_invalid_request(self): """Test processing invalid request structure.""" server = JsonRpcServer("test-server") # Missing method result = server._process_request('{"jsonrpc": "2.0", "id": 1}') assert result["error"]["code"] == ERROR_INVALID_REQUEST # ID should be preserved but currently it's None due to parse order assert result["id"] is None # This is the current behavior def test_process_request_method_not_found(self): """Test processing request with unknown method.""" server = JsonRpcServer("test-server") request = {"jsonrpc": "2.0", "method": "unknown_method", "id": 1} result = server._process_request(json.dumps(request)) assert result["error"]["code"] == ERROR_METHOD_NOT_FOUND assert "unknown_method" in result["error"]["message"] assert result["id"] == 1 def test_process_request_handler_success(self): """Test successful handler execution.""" server = JsonRpcServer("test-server") handler_result = {"jsonrpc": "2.0", "result": {"data": "test"}, "id": 1} handler = MagicMock(return_value=handler_result) server.register_handler("test_method", handler) request = {"jsonrpc": "2.0", "method": "test_method", "params": {"foo": "bar"}, "id": 1} result = server._process_request(json.dumps(request)) handler.assert_called_once_with(1, {"foo": "bar"}) assert result == handler_result def test_process_request_handler_exception(self): """Test handler raising exception.""" server = JsonRpcServer("test-server") handler = MagicMock(side_effect=Exception("Handler error")) server.register_handler("test_method", handler) request = {"jsonrpc": "2.0", "method": "test_method", "id": 1} result = server._process_request(json.dumps(request)) assert result["error"]["code"] == ERROR_INTERNAL assert "Handler error" in result["error"]["message"] assert result["id"] == 1 def test_process_request_notification(self): """Test processing notification (no id).""" server = JsonRpcServer("test-server") handler_result = {"jsonrpc": "2.0", "result": "ok"} handler = MagicMock(return_value=handler_result) server.register_handler("notify", handler) request = {"jsonrpc": "2.0", "method": "notify", "params": {}} result = server._process_request(json.dumps(request)) handler.assert_called_once_with(None, {}) assert result == handler_result @patch("sys.stdin") @patch("builtins.print") def test_run_single_request(self, mock_print, mock_stdin): """Test running server with a single request.""" server = JsonRpcServer("test-server") handler = MagicMock(return_value={"jsonrpc": "2.0", "result": "ok", "id": 1}) server.register_handler("test", handler) # Simulate one request then EOF mock_stdin.readline.side_effect = [ '{"jsonrpc": "2.0", "method": "test", "id": 1}\n', "", # EOF ] server.run() # Verify handler was called handler.assert_called_once() # Verify response was written mock_print.assert_called_with('{"jsonrpc": "2.0", "result": "ok", "id": 1}', flush=True) def test_stop(self): """Test stopping the server.""" server = JsonRpcServer("test-server") server._running = True server.stop() assert server._running is False class TestHelperFunctions: """Test helper functions.""" def test_create_result_response(self): """Test create_result_response helper.""" response = create_result_response(123, {"data": "test"}) assert response == {"jsonrpc": "2.0", "result": {"data": "test"}, "id": 123} def test_create_result_response_with_none_id(self): """Test create_result_response with None id.""" response = create_result_response(None, "result") assert response == {"jsonrpc": "2.0", "result": "result", "id": None} def test_create_error_response(self): """Test create_error_response helper.""" response = create_error_response(42, ERROR_METHOD_NOT_FOUND, "Method not found") assert response == { "jsonrpc": "2.0", "id": 42, "error": {"code": ERROR_METHOD_NOT_FOUND, "message": "Method not found"}, } def test_create_text_content(self): """Test create_text_content helper.""" content = create_text_content("Hello, world!") assert content == {"type": "text", "text": "Hello, world!"} def test_create_tool(self): """Test create_tool helper.""" tool = create_tool( name="test_tool", description="A test tool", input_schema={"type": "object", "properties": {"param1": {"type": "string"}}}, ) assert tool == { "name": "test_tool", "description": "A test tool", "inputSchema": {"type": "object", "properties": {"param1": {"type": "string"}}}, }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/lbds137/gemini-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server