async def test_batch(): reg = RpcRegistry() @reg.method() async def echo(text: str) -> str: return 'echo: %s' % text @reg.method() async def err() -> None: raise Exception('some error', {'pay': 'load'}) ex = JsonRpcExecutor(reg, get_app()) res = await ex.exec( b'[{"jsonrpc": "2.0", ' b'"method": "echo", "params": {"text": "1"}, "id": 1},' b'{"jsonrpc": "2.0", ' b'"method": "err", "params": {}, "id": 3},' b'{"jsonrpc": "2.0", ' b'"method": "echo", "params": {"text": "2"}, "id": 2}]' ) assert json.loads(res) == [ {"jsonrpc": "2.0", "id": 1, "result": "echo: 1"}, { "jsonrpc": "2.0", "id": 3, "error": { "message": "some error", "code": -32000, "data": {"pay": "load"}, }, }, {"jsonrpc": "2.0", "id": 2, "result": "echo: 2"}, ]
async def test_err_invalid_req_2(): reg = RpcRegistry() ex = JsonRpcExecutor(reg, get_app()) res = await ex.exec(b'{"params": []}') assert json.loads(res) == { "jsonrpc": "2.0", "id": None, "error": {"message": "Invalid Request", "code": -32600}, }
async def test_err_parse_1(): reg = RpcRegistry() ex = JsonRpcExecutor(reg, get_app()) res = await ex.exec(b'eeeee') assert json.loads(res) == { "jsonrpc": "2.0", "id": None, "error": {"message": "Parse error", "code": -32700}, }
async def prepare(self) -> None: await self.queue_declare( self.cfg.queue, False, self.cfg.queue_durable, False, self.cfg.queue_auto_delete, self.cfg.queue_arguments, ) await self.qos(prefetch_count=self.cfg.prefetch_count) self._lock = asyncio.Lock() self._rpc = JsonRpcExecutor(self.registry, self.amqp.app)
async def test_notification(): reg = RpcRegistry() @reg.method() async def echo(self, text: str) -> str: return text ex = JsonRpcExecutor(reg, get_app()) res = await ex.exec( b'{"jsonrpc": "2.0",' b' "method": "echo", "params": {"text": "123"}}' ) assert res == b''
async def test_error_method(): reg = RpcRegistry() ex = JsonRpcExecutor(reg, get_app()) res = await ex.exec( b'{"jsonrpc": "2.0",' b' "method": "echo", "params": {"text": "123"}, "id": 10}' ) assert json.loads(res) == { 'error': {'code': -32601, 'message': 'Method not found'}, 'id': 10, 'jsonrpc': '2.0', }
async def test_legacy_v1_format_success_2(): reg = RpcRegistry() @reg.method() async def noop(text: str) -> None: pass ex = JsonRpcExecutor(reg, get_app()) res = await ex.exec(b'{"method": "noop", "text": "123"}') assert json.loads(res) == { 'code': 0, 'message': 'OK', }
async def test_legacy_v1_format_error(): reg = RpcRegistry() @reg.method() async def echo(text: str) -> None: return None ex = JsonRpcExecutor(reg, get_app()) res = await ex.exec(b'{"method": "echo", "int": 1}') assert json.loads(res) == { 'code': -32602, 'message': 'Invalid params', 'info': 'Got an unexpected argument: int', }
async def test_legacy_v2_format_success(): reg = RpcRegistry() @reg.method() async def echo(text: str) -> str: return 'echo: %s' % text ex = JsonRpcExecutor(reg, get_app()) res = await ex.exec(b'{"method": "echo", "params": {"text": "123"}}') assert json.loads(res) == { 'code': 0, 'message': 'OK', 'result': 'echo: 123', }
async def test_legacy_v2_format_error(): reg = RpcRegistry() @reg.method() async def echo(text: str) -> str: return 'echo: %s' % text ex = JsonRpcExecutor(reg, get_app()) res = await ex.exec(b'{"method": "echo", "params": {}}') assert json.loads(res) == { 'code': -32602, 'details': {'info': 'Missing 1 required argument(s): text'}, 'message': 'Invalid params', }
async def test_error_with_data(): reg = RpcRegistry() @reg.method() async def echo(text: str) -> str: raise Exception('Ex', 'some data') ex = JsonRpcExecutor(reg, get_app()) res = await ex.exec( b'{"jsonrpc": "2.0",' b' "method": "echo", "params": {"text": "123"}, "id": 10}' ) assert json.loads(res) == { 'error': {'code': -32000, 'data': 'some data', 'message': 'Ex'}, 'id': 10, 'jsonrpc': '2.0', }
async def test_batch_notification(): reg = RpcRegistry() @reg.method() async def echo(text: str) -> str: return 'echo: %s' % text @reg.method() async def err() -> None: raise Exception('some error', {'pay': 'load'}) ex = JsonRpcExecutor(reg, get_app()) res = await ex.exec( b'[{"jsonrpc": "2.0", "method": "echo", "params": {"text": "1"}},' b'{"jsonrpc": "2.0", "method": "err", "params": {}}]' ) assert res == b''
async def test_success_by_pos_default(): reg = RpcRegistry() @reg.method() async def sum(a: int, b: int, c: int = 3) -> int: return a + b + c ex = JsonRpcExecutor(reg, get_app()) res = await ex.exec( b'{"jsonrpc": "2.0",' b' "method": "sum", "params": [1,2], "id": 10}' ) assert json.loads(res) == { "jsonrpc": "2.0", "id": 10, "result": 6, }
async def test_batch_complicated(): reg = RpcRegistry() @reg.method() async def echo(text: str) -> str: return 'echo: %s' % text @reg.method() async def err() -> None: raise Exception('some error', {'pay': 'load'}) ex = JsonRpcExecutor(reg, get_app()) res = await ex.exec( b'[{"jsonrpc": "2.0", ' b'"method": "echo", "params": {"text": "1"},"id":"1"},' b'{"jsonrpc": "2.0", ' b'"method": "echo", "params": {"text": "2"}},' b'{"jsonrpc": "2.0", ' b'"method": "echo", "params": {"text": "3"},"id":3},' b'{"foo": "boo"},' b'{"jsonrpc": "2.0", ' b'"method": "err", "params": {}},' b'{"jsonrpc": "2.0", ' b'"method": "notfound1", "params": {}},' b'{"jsonrpc": "2.0", ' b'"method": "notfound2", "params": {},"id":7},' b'{"jsonrpc": "2.0", ' b'"method": "echo", "params": {"text": "8"},"id":8}]' ) assert json.loads(res) == [ {"jsonrpc": "2.0", "id": "1", "result": "echo: 1"}, {"jsonrpc": "2.0", "id": 3, "result": "echo: 3"}, { "jsonrpc": "2.0", "id": None, "error": {"message": "Invalid Request", "code": -32600}, }, { "jsonrpc": "2.0", "id": 7, "error": {"message": "Method not found", "code": -32601}, }, {"jsonrpc": "2.0", "id": 8, "result": "echo: 8"}, ]
async def test_success_by_name(): reg = RpcRegistry() @reg.method() async def echo(text: str) -> str: return 'echo: %s' % text ex = JsonRpcExecutor(reg, get_app()) res = await ex.exec( b'{"jsonrpc": "2.0",' b' "method": "echo", "params": {"text": "123"}, "id": 10}' ) assert json.loads(res) == { "jsonrpc": "2.0", "id": 10, "result": "echo: 123", }
async def test_legacy_v1_custom_error(): class MyJsonRpcError(JsonRpcError): jsonrpc_error_code = 1 message = 'Something wrong' reg = RpcRegistry() @reg.method() async def echo(text: str) -> None: raise MyJsonRpcError() ex = JsonRpcExecutor(reg, get_app()) res = await ex.exec(b'{"method": "echo", "text": ""}') assert json.loads(res) == { 'code': 1, 'message': 'Something wrong', }
async def test_error_params_by_pos(): reg = RpcRegistry() @reg.method() async def echo(text: str, a: int) -> str: raise Exception('Ex') ex = JsonRpcExecutor(reg, get_app()) res = await ex.exec( b'{"jsonrpc": "2.0",' b' "method": "echo", "params": [], "id": 10}' ) assert json.loads(res) == { 'error': { 'code': -32602, 'data': {'info': 'Missing 2 required argument(s): text, a'}, 'message': 'Invalid params', }, 'id': 10, 'jsonrpc': '2.0', }
async def test_error_unexpected_params(): reg = RpcRegistry() @reg.method() async def echo(a: int) -> str: raise Exception('Ex') ex = JsonRpcExecutor(reg, get_app()) res = await ex.exec( b'{"jsonrpc": "2.0",' b' "method": "echo", ' b'"params": {"a":1,"b":2}, "id": 10}' ) assert json.loads(res) == { 'error': { 'code': -32602, 'data': {'info': 'Got an unexpected argument: b'}, 'message': 'Invalid params', }, 'id': 10, 'jsonrpc': '2.0', }
async def test_error_unexpected_params_by_pos(): reg = RpcRegistry() @reg.method() async def echo(a: int, b: int = 2) -> str: raise Exception('Ex') ex = JsonRpcExecutor(reg, get_app()) res = await ex.exec( b'{"jsonrpc": "2.0",' b' "method": "echo", ' b'"params": [1,2,3], "id": 10}' ) assert json.loads(res) == { 'error': { 'code': -32602, 'data': { 'info': 'Method takes 2 positional arguments but 3 were given' }, 'message': 'Invalid params', }, 'id': 10, 'jsonrpc': '2.0', }
async def transport(request: bytes, timeout: Optional[float]) -> bytes: ex = JsonRpcExecutor(reg, app) return await ex.exec(request)
def serialize(self) -> bytes: return json.dumps(JsonRpcExecutor.cast2dump(self._to_dict())).encode()
async def test_discover(): class Address(BaseModel): inline: str index: str class User(BaseModel): address: Address name: str class Err111(JsonRpcError): jsonrpc_error_code = 111 message = "My Error 111" class Err222(JsonRpcError): jsonrpc_error_code = 222 message = "My Error 222" reg = RpcRegistry( title='Api for tests', description='Log description\nof api', version='1.0', ) @reg.method(deprecated=True) async def echo(text: str) -> str: return 'echo: %s' % text @reg.method() async def get_user(id: int) -> User: return User( name='test', address={'inline': 'Moscow, Kremlin, 1', 'index': '123456'}, ) @reg.method(errors=[Err111, Err222]) async def add_user(user: User) -> int: """ Add user Метод добавляет нового пользователи и возвращает его идентификатор :param user: объект пользователя :return: идентифиатор пользователя """ return 1 ex = JsonRpcExecutor(reg, get_app(), discover_enabled=True) res = await ex.exec( b'{"jsonrpc": "2.0",' b' "method": "rpc.discover", "id": 10}' ) assert json.loads(res) == { 'result': { 'openrpc': '1.2.4', 'info': { 'version': '1.0', 'title': 'Api for tests', 'description': 'Log description\nof api', }, 'methods': [ { 'description': 'Метод добавляет нового\n' 'пользователи и возвращает его\n' 'идентификатор', 'result': { 'required': True, 'schema': {'title': 'Result', 'type': 'integer'}, 'name': 'result', "summary": "идентифиатор пользователя", }, 'summary': 'Add user', 'name': 'add_user', 'paramStructure': 'by-name', 'errors': [ {'code': 111, 'data': None, 'message': 'My Error 111'}, {'code': 222, 'data': None, 'message': 'My Error 222'}, ], 'params': [ { 'required': True, 'summary': 'объект пользователя', 'schema': {'$ref': '#/components/schemas/User'}, 'name': 'user', } ], }, { 'result': { 'required': True, 'schema': {'title': 'Result', 'type': 'string'}, 'name': 'result', }, 'deprecated': True, 'params': [ { 'required': True, 'schema': {'title': 'Text', 'type': 'string'}, 'name': 'text', } ], 'name': 'echo', 'paramStructure': 'by-name', }, { 'result': { 'required': True, 'schema': {'$ref': '#/components/schemas/User'}, 'name': 'result', }, 'params': [ { 'required': True, 'schema': {'title': 'Id', 'type': 'integer'}, 'name': 'id', } ], 'name': 'get_user', 'paramStructure': 'by-name', }, ], 'components': { 'schemas': { 'User': { 'required': ['address', 'name'], 'properties': { 'address': { '$ref': '#/components/schemas/Address' }, 'name': {'title': 'Name', 'type': 'string'}, }, 'title': 'User', 'type': 'object', }, 'Address': { 'required': ['inline', 'index'], 'properties': { 'inline': {'title': 'Inline', 'type': 'string'}, 'index': {'title': 'Index', 'type': 'string'}, }, 'title': 'Address', 'type': 'object', }, } }, }, 'id': 10, 'jsonrpc': '2.0', }