async def test_rpc_call_with_an_invalid_batch(aiohttp_client, mocker): """ --> [1] <-- {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null} """ rpc_server = aiohttp_rpc.WsJsonRpcServer() client = await utils.make_ws_client(aiohttp_client, rpc_server) future = asyncio.Future() def unprocessed_json_response_handler(*, ws_connect, ws_msg, json_response): future.set_result(json_response) assert json_response == { 'jsonrpc': '2.0', 'error': { 'code': -32600, 'message': 'Data must be a dict.' }, 'id': None, } async with aiohttp_rpc.WsJsonRpcClient( '/rpc', session=client, unprocessed_json_response_handler=unprocessed_json_response_handler, ) as rpc: handle_ws_message = mocker.patch.object( rpc, '_handle_single_ws_message', side_effect=rpc._handle_single_ws_message, ) await rpc.send_json([1]) await asyncio.wait_for(future, timeout=3) handle_ws_message.assert_called_once()
async def test_notification(aiohttp_client): """ --> {"jsonrpc": "2.0", "method": "update", "params": [1,2,3,4,5]} --> {"jsonrpc": "2.0", "method": "foobar"} """ def update(*args): return args def foobar(*args): return 'ok' rpc_server = aiohttp_rpc.WsJsonRpcServer() rpc_server.add_method(update) rpc_server.add_method(foobar) client = await utils.make_ws_client(aiohttp_client, rpc_server) async with aiohttp_rpc.WsJsonRpcClient('/rpc', session=client) as rpc: assert await rpc.notify('update', subtrahend=23, minuend=42) is None assert await rpc.notify('foobar', minuend=42, subtrahend=23) is None result = await rpc.send_json({ 'jsonrpc': '2.0', 'method': 'update', 'params': [1, 2, 3, 4, 5] }) assert result[0] is None result = await rpc.send_json({'jsonrpc': '2.0', 'method': 'foobar'}) assert result[0] is None
async def test_rpc_call_of_non_existent_method(aiohttp_client): """ --> {"jsonrpc": "2.0", "method": "foobar", "id": "1"} <-- {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "1"} """ rpc_server = aiohttp_rpc.WsJsonRpcServer() client = await utils.make_ws_client(aiohttp_client, rpc_server) async with aiohttp_rpc.WsJsonRpcClient('/rpc', session=client) as rpc: with pytest.raises(errors.MethodNotFound): assert await rpc.call('foobar', subtrahend=23, minuend=42) result = await rpc.send_json({ 'jsonrpc': '2.0', 'method': 'foobar', 'id': '1' }) assert result[0] == { 'jsonrpc': '2.0', 'error': { 'code': -32601, 'message': errors.MethodNotFound.message }, 'id': '1', }
async def test_rpc_call_with_positional_parameters(aiohttp_client): """ --> {"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1} <-- {"jsonrpc": "2.0", "result": 19, "id": 1} --> {"jsonrpc": "2.0", "method": "subtract", "params": [23, 42], "id": 2} <-- {"jsonrpc": "2.0", "result": -19, "id": 2} """ def subtract(a, b): return a - b rpc_server = aiohttp_rpc.WsJsonRpcServer() rpc_server.add_method(subtract) client = await utils.make_ws_client(aiohttp_client, rpc_server) async with aiohttp_rpc.WsJsonRpcClient('/rpc', session=client) as rpc: assert await rpc.subtract(42, 23) == 19 assert await rpc.subtract(23, 42) == -19 result = await rpc.send_json({ 'jsonrpc': '2.0', 'method': 'subtract', 'params': [42, 23], 'id': 1 }) assert result[0] == {'jsonrpc': '2.0', 'result': 19, 'id': 1} result = await rpc.send_json({ 'jsonrpc': '2.0', 'method': 'subtract', 'params': [23, 42], 'id': 2 }) assert result[0] == {'jsonrpc': '2.0', 'result': -19, 'id': 2}
async def test_args(aiohttp_client): def method(a=1): return [1, 2, a] rpc_server = aiohttp_rpc.WsJsonRpcServer() rpc_server.add_method(method) client = await utils.make_ws_client(aiohttp_client, rpc_server) async with aiohttp_rpc.WsJsonRpcClient('/rpc', session=client) as rpc: assert await rpc.call('method') == [1, 2, 1] assert await rpc.call('method', 1) == [1, 2, 1]
async def test_batch(aiohttp_client): def method_1(a=1): return [1, a] def method_2(): return 1 rpc_server = aiohttp_rpc.WsJsonRpcServer() rpc_server.add_methods(( method_1, method_2, )) client = await utils.make_ws_client(aiohttp_client, rpc_server) async with aiohttp_rpc.WsJsonRpcClient('/rpc', session=client) as rpc: assert await rpc.batch(( 'method_1', 'method_2', )) == [[1, 1], 1] assert await rpc.batch(( ('method_1', 4), ( 'method_1', [], { 'a': 5 }, ), )) == [[1, 4], [1, 5]] async with aiohttp_rpc.WsJsonRpcClient('/rpc', session=client) as rpc: assert await rpc.batch_notify(( 'method_1', 'method_2', )) is None assert await rpc.batch_notify(( ('method_1', 4), ( 'method_1', [], { 'a': 5 }, ), )) is None
async def test_rpc_call_with_invalid_json(aiohttp_client, mocker): """ --> {"jsonrpc": "2.0", "method": "foobar, "params": "bar", "baz] <-- {"jsonrpc": "2.0", "error": {"code": -32700, "message": "Parse error"}, "id": null} """ rpc_server = aiohttp_rpc.WsJsonRpcServer() client = await utils.make_ws_client(aiohttp_client, rpc_server) future = asyncio.Future() def unprocessed_json_response_handler(*, ws_connect, ws_msg, json_response): future.set_result(json_response) del json_response['error']['message'] assert json_response == { 'jsonrpc': '2.0', 'error': { 'code': -32700 }, 'id': None } async with aiohttp_rpc.WsJsonRpcClient( '/rpc', session=client, unprocessed_json_response_handler=unprocessed_json_response_handler, ) as rpc: handle_ws_message = mocker.patch.object( rpc, '_handle_single_ws_message', side_effect=rpc._handle_single_ws_message, ) rpc.json_serialize = lambda x: x result = await rpc.send_json( '{"jsonrpc": "2.0", "method": "foobar, "params": "bar", "baz]') assert result == ( None, None, ) await asyncio.wait_for(future, timeout=3) handle_ws_message.assert_called_once()
async def test_several_requests(aiohttp_client): async def method(a): await asyncio.sleep(0.2) return a rpc_server = aiohttp_rpc.WsJsonRpcServer() rpc_server.add_method(method) client = await utils.make_ws_client(aiohttp_client, rpc_server) async with aiohttp_rpc.WsJsonRpcClient('/rpc', session=client) as rpc: started_at = datetime.datetime.now() result = await asyncio.gather(*(rpc.call('method', i) for i in range(10))) finished_at = datetime.datetime.now() assert finished_at - started_at < datetime.timedelta(seconds=1) assert result == list(range(10))
async def test_rpc_call_with_named_parameters(aiohttp_client): """ --> {"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id": 3} <-- {"jsonrpc": "2.0", "result": 19, "id": 3} --> {"jsonrpc": "2.0", "method": "subtract", "params": {"minuend": 42, "subtrahend": 23}, "id": 4} <-- {"jsonrpc": "2.0", "result": 19, "id": 4} """ def subtract(*, subtrahend, minuend): return minuend - subtrahend rpc_server = aiohttp_rpc.WsJsonRpcServer() rpc_server.add_method(subtract) client = await utils.make_ws_client(aiohttp_client, rpc_server) async with aiohttp_rpc.WsJsonRpcClient('/rpc', session=client) as rpc: assert await rpc.subtract(subtrahend=23, minuend=42) == 19 assert await rpc.subtract(minuend=42, subtrahend=23) == 19 result = await rpc.send_json({ 'jsonrpc': '2.0', 'method': 'subtract', 'params': { "subtrahend": 23, "minuend": 42 }, 'id': 3, }) assert result[0] == {'jsonrpc': '2.0', 'result': 19, 'id': 3} result = await rpc.send_json({ 'jsonrpc': '2.0', 'method': 'subtract', 'params': { "minuend": 42, "subtrahend": 23 }, 'id': 4 }) assert result[0] == {'jsonrpc': '2.0', 'result': 19, 'id': 4}
async def test_ws_client_for_server_response(aiohttp_client, mocker): async def method(rpc_ws_client: aiohttp_rpc.WsJsonRpcClient): await rpc_ws_client.notify('ping') await rpc_ws_client.notify('ping') await rpc_ws_client.notify('ping') rpc_server = aiohttp_rpc.WsJsonRpcServer(middlewares=[ *aiohttp_rpc.middlewares.DEFAULT_MIDDLEWARES, aiohttp_rpc.middlewares.ws_client_for_server_response, ], ) rpc_server.add_method(method) client = await utils.make_ws_client(aiohttp_client, rpc_server) future = asyncio.Future() results = [] def json_request_handler(*, ws_connect, ws_msg, json_request): results.append(json_request) if len(results) == 3: future.set_result(results) async with aiohttp_rpc.WsJsonRpcClient( '/rpc', session=client, json_request_handler=json_request_handler, ) as rpc: json_request_handler = mocker.patch.object( rpc, '_json_request_handler', side_effect=rpc._json_request_handler) await rpc.method() await asyncio.wait_for(future, timeout=3) assert json_request_handler.call_count == 3 assert results[0]['method'] == 'ping' assert results[1]['method'] == 'ping' assert results[2]['method'] == 'ping'
async def test_rpc_call_with_invalid_batch(aiohttp_client): """ --> [ {"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"}, {"jsonrpc": "2.0", "method": "notify_hello", "params": [7]}, {"jsonrpc": "2.0", "method": "subtract", "params": [42,23], "id": "2"}, {"foo": "boo"}, {"jsonrpc": "2.0", "method": "foo.get", "params": {"name": "myself"}, "id": "5"}, {"jsonrpc": "2.0", "method": "get_data", "id": "9"} ] <-- [ {"jsonrpc": "2.0", "result": 7, "id": "1"}, {"jsonrpc": "2.0", "result": 19, "id": "2"}, {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}, {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "5"}, {"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"} ] """ def subtract(a, b): return a - b def notify_hello(a): return a def get_data(): return ['hello', 5] def my_sum(*args): return sum(args) rpc_server = aiohttp_rpc.WsJsonRpcServer() rpc_server.add_method(subtract) rpc_server.add_method((aiohttp_rpc.JsonRpcMethod(prefix='', func=my_sum, custom_name='sum'))) rpc_server.add_method(notify_hello) rpc_server.add_method(get_data) client = await utils.make_ws_client(aiohttp_client, rpc_server) called_methods = [ aiohttp_rpc.JsonRpcRequest(id=1, method_name='sum', params=[1, 2, 4]), aiohttp_rpc.JsonRpcRequest(method_name='notify_hello', params=[1, 2, 4]), aiohttp_rpc.JsonRpcRequest(id=2, method_name='subtract', params=[42, 23]), aiohttp_rpc.JsonRpcRequest(id=5, method_name='foo.get', params={'name': 'myself'}), aiohttp_rpc.JsonRpcRequest(id=9, method_name='get_data'), ] async with aiohttp_rpc.WsJsonRpcClient('/rpc', session=client) as rpc: assert await rpc.batch(called_methods) == [ 7, None, 19, errors.MethodNotFound(), ['hello', 5] ] assert await rpc.batch(called_methods, save_order=False) == [ 7, 19, errors.MethodNotFound(), ['hello', 5] ] result = await rpc.send_json([{ 'jsonrpc': '2.0', 'method': 'sum', 'params': [1, 2, 4], 'id': '1' }, { 'jsonrpc': '2.0', 'method': 'notify_hello', 'params': [7] }, { 'jsonrpc': '2.0', 'method': 'subtract', 'params': [42, 23], 'id': '2' }, { 'foo': 'boo' }, { 'jsonrpc': '2.0', 'method': 'foo.get', 'params': { 'name': 'myself' }, 'id': '5' }, { 'jsonrpc': '2.0', 'method': 'get_data', 'id': '9' }]) assert result[0] == [ { 'jsonrpc': '2.0', 'result': 7, 'id': '1' }, { 'jsonrpc': '2.0', 'result': 19, 'id': '2' }, { 'jsonrpc': '2.0', 'error': { 'code': -32600, 'message': 'A request must contain "method" and "jsonrpc".' }, 'id': None }, { 'jsonrpc': '2.0', 'error': { 'code': -32601, 'message': 'The method does not exist / is not available.' }, 'id': '5' }, { 'jsonrpc': '2.0', 'result': ['hello', 5], 'id': '9' }, ]