async def test_batch(aiohttp_client): def method_1(a=1): return [1, 2, a] def method_2(): return [1] rpc_server = aiohttp_rpc.JsonRpcServer() rpc_server.add_methods(( method_1, method_2, )) assert await rpc_server.call('method_1') == [1, 2, 1] assert await rpc_server.call('method_2') == [1] client = await utils.make_client(aiohttp_client, rpc_server) async with aiohttp_rpc.JsonRpcClient('/rpc', session=client) as rpc: assert await rpc.batch(( 'method_1', 'method_2', )) == [[1, 2, 1], [1]] assert await rpc.batch(( ('method_1', 4), ('method_1', [], { 'a': 5 }), )) == [[1, 2, 4], [1, 2, 5]]
async def test_rpc_call_with_invalid_batch(aiohttp_client): """ --> [1,2,3] <-- [ {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}, {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}, {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null} ] """ rpc_server = aiohttp_rpc.JsonRpcServer() client = await utils.make_client(aiohttp_client, rpc_server) json_with_error = { 'jsonrpc': '2.0', 'error': { 'code': -32600, 'message': 'Data must be a dict or an list.' }, 'id': None, } async with aiohttp_rpc.JsonRpcClient('/rpc', session=client) as rpc: result = await rpc.send_json([1, 2, 3]) assert result[0] == [json_with_error, json_with_error, json_with_error]
async def test_rpc_call_with_invalid_json(aiohttp_client): """ --> {"jsonrpc": "2.0", "method": "foobar, "params": "bar", "baz] <-- {"jsonrpc": "2.0", "error": {"code": -32700, "message": "Parse error"}, "id": null} """ rpc_server = aiohttp_rpc.JsonRpcServer() client = await utils.make_client(aiohttp_client, rpc_server) async with aiohttp_rpc.JsonRpcClient('/rpc', session=client) as rpc: http_response = await rpc.session.post( rpc.url, data='{"jsonrpc": "2.0", "method": "foobar, "params": "bar", "baz]', ) json_response = await http_response.json() del json_response['error']['message'] assert json_response == { 'jsonrpc': '2.0', 'error': { 'code': -32700 }, 'id': None }
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.JsonRpcServer() rpc_server.add_method(update) rpc_server.add_method(foobar) client = await utils.make_client(aiohttp_client, rpc_server) async with aiohttp_rpc.JsonRpcClient('/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_extra_kwargs_with_wrapper(aiohttp_client): def test_decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper @test_decorator def method(rpc_request): return rpc_request.__class__.__name__ @test_decorator def method_2(): return True rpc_server = aiohttp_rpc.JsonRpcServer( middlewares=(aiohttp_rpc.middlewares.extra_args_middleware, )) rpc_server.add_methods(( method, method_2, )) client = await utils.make_client(aiohttp_client, rpc_server) async with aiohttp_rpc.JsonRpcClient('/rpc', session=client) as rpc: assert await rpc.call('method') == 'JsonRpcRequest' assert await rpc.call('method_2') is True
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.JsonRpcServer() client = await utils.make_client(aiohttp_client, rpc_server) async with aiohttp_rpc.JsonRpcClient('/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.JsonRpcServer() rpc_server.add_method(subtract) client = await utils.make_client(aiohttp_client, rpc_server) async with aiohttp_rpc.JsonRpcClient('/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_builtin_funcs(aiohttp_client): rpc_server = aiohttp_rpc.JsonRpcServer( middlewares=(aiohttp_rpc.middlewares.extra_args_middleware, )) rpc_server.add_method(sum) rpc_server.add_method( aiohttp_rpc.JsonRpcMethod('', zip, prepare_result=list)) client = await utils.make_client(aiohttp_client, rpc_server) async with aiohttp_rpc.JsonRpcClient('/rpc', session=client) as rpc: assert await rpc.sum([1, 2, 3]) == 6 assert await rpc.zip(['a', 'b'], [1, 2]) == [['a', 1], ['b', 2]]
async def test_adding_methods(): def method_1(): pass def method_2(): pass rpc_server = aiohttp_rpc.JsonRpcServer() rpc_server.add_methods([method_1, method_2]) assert rpc_server.methods['method_1'].func == method_1 assert rpc_server.methods['method_2'].func == method_2
async def test_args(aiohttp_client): def method(a=1): return [1, 2, a] rpc_server = aiohttp_rpc.JsonRpcServer() rpc_server.add_method(method) assert await rpc_server.call('method') == [1, 2, 1] assert await rpc_server.call('method', args=[1]) == [1, 2, 1] client = await utils.make_client(aiohttp_client, rpc_server) async with aiohttp_rpc.JsonRpcClient('/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_varargs(aiohttp_client): def method(a=1, *args): return [a, *args] rpc_server = aiohttp_rpc.JsonRpcServer() rpc_server.add_method(method) assert await rpc_server.call('method') == [1] assert await rpc_server.call('method', args=[2]) == [2] assert await rpc_server.call('method', args=[2, 3]) == [2, 3] client = await utils.make_client(aiohttp_client, rpc_server) async with aiohttp_rpc.JsonRpcClient('/rpc', session=client) as rpc: assert await rpc.call('method') == [1] assert await rpc.call('method', 2) == [2] assert await rpc.call('method', 2, 3) == [2, 3]
async def test_extra_kwargs_with_class(aiohttp_client): class TestClass: def __init__(self, rpc_request): self.rpc_request = rpc_request def __str__(self): return self.rpc_request.__class__.__name__ rpc_server = aiohttp_rpc.JsonRpcServer( middlewares=(aiohttp_rpc.middlewares.extra_args_middleware, )) rpc_server.add_method( aiohttp_rpc.JsonRpcMethod('', TestClass, prepare_result=str)) client = await utils.make_client(aiohttp_client, rpc_server) async with aiohttp_rpc.JsonRpcClient('/rpc', session=client) as rpc: assert await rpc.call('TestClass') == 'JsonRpcRequest'
async def test_middleware(aiohttp_client): def method(): return 'ok' async def test_middleware(request, handler): request.method_name = 'method' response = await handler(request) response.result += '!' return response rpc_server = aiohttp_rpc.JsonRpcServer(middlewares=(test_middleware, )) rpc_server.add_method(method) client = await utils.make_client(aiohttp_client, rpc_server) async with aiohttp_rpc.JsonRpcClient('/rpc', session=client) as rpc: assert await rpc.call('my_method') == 'ok!'
async def test_adding_method(): def method(): pass class TestClass: def method_1(self): pass @classmethod def method_2(cls): pass @staticmethod def method_3(): pass rpc_server = aiohttp_rpc.JsonRpcServer() rpc_server.add_method(method) assert rpc_server.methods['method'].func == method rpc_server.add_method(['test', method]) assert rpc_server.methods['test__method'].func == method rpc_server.add_method(aiohttp_rpc.JsonRpcMethod('test_2', method)) assert rpc_server.methods['test_2__method'].func == method rpc_server.add_method(aiohttp_rpc.JsonRpcMethod('', method, custom_name='test')) assert rpc_server.methods['test'].func == method rpc_server.add_method(aiohttp_rpc.JsonRpcMethod('test', method, custom_name='test')) assert rpc_server.methods['test__test'].func == method test_class = TestClass() rpc_server.add_method(test_class.method_1) assert rpc_server.methods['method_1'].func == test_class.method_1 rpc_server.add_method(TestClass.method_2) assert rpc_server.methods['method_2'].func == TestClass.method_2 rpc_server.add_method(TestClass.method_3) assert rpc_server.methods['method_3'].func == TestClass.method_3
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.JsonRpcServer() rpc_server.add_method(subtract) client = await utils.make_client(aiohttp_client, rpc_server) async with aiohttp_rpc.JsonRpcClient('/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_extra_kwargs(aiohttp_client): def method(rpc_request): return rpc_request.__class__.__name__ def method_2(*, rpc_request): return rpc_request.__class__.__name__ rpc_server = aiohttp_rpc.JsonRpcServer( middlewares=(aiohttp_rpc.middlewares.extra_args_middleware, )) rpc_server.add_method(method) rpc_server.add_method(method_2) assert await rpc_server.call('method', extra_args={'rpc_request': 123}), 123 assert await rpc_server.call('method_2', extra_args={'rpc_request': 123}), 123 client = await utils.make_client(aiohttp_client, rpc_server) async with aiohttp_rpc.JsonRpcClient('/rpc', session=client) as rpc: assert await rpc.call('method') == 'JsonRpcRequest' assert await rpc.call('method_2') == 'JsonRpcRequest'
async def test_rpc_call_with_an_empty_array(aiohttp_client): """ --> [] <-- {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null} """ rpc_server = aiohttp_rpc.JsonRpcServer() client = await utils.make_client(aiohttp_client, rpc_server) async with aiohttp_rpc.JsonRpcClient('/rpc', session=client) as rpc: with pytest.raises(errors.InvalidRequest): await rpc.batch([]) result = await rpc.send_json([]) assert result[0] == { 'jsonrpc': '2.0', 'error': { 'code': -32600, 'message': errors.InvalidRequest.message }, 'id': None, }
async def test_varkw(aiohttp_client): def method(a=1, **kwargs): return [a, kwargs] rpc_server = aiohttp_rpc.JsonRpcServer() rpc_server.add_method(method) with pytest.raises(errors.InvalidParams): await rpc_server.call('method', args=[1, 2]) assert await rpc_server.call('method', kwargs={ 'a': 1, 'b': 2 }) == [1, { 'b': 2 }] client = await utils.make_client(aiohttp_client, rpc_server) async with aiohttp_rpc.JsonRpcClient('/rpc', session=client) as rpc: with pytest.raises(errors.InvalidParams): await rpc.call('method', 1, 2) assert await rpc.call('method', a=1, b=2) == [1, {'b': 2}]
async def test_unlinked_results(aiohttp_client, mocker): def method_1(a=1): return [1, 2, a] def method_2(): return [1] rpc_server = aiohttp_rpc.JsonRpcServer() rpc_server.add_methods(( method_1, method_2, )) client = await utils.make_client(aiohttp_client, rpc_server) async def test_send_json_1(data, **kwargs): data = [ { 'id': None, 'jsonrpc': '2.0', 'result': [1] }, { 'id': data[0]['id'], 'jsonrpc': '2.0', 'result': [1, 2, 1] }, ] return data, {} async def test_send_json_2(data, **kwargs): data = [ { 'id': None, 'jsonrpc': '2.0', 'result': [1] }, { 'id': data[0]['id'], 'jsonrpc': '2.0', 'result': [1, 2, 1] }, { 'id': None, 'jsonrpc': '2.0', 'result': [1] }, ] return data, {} async with aiohttp_rpc.JsonRpcClient('/rpc', session=client) as rpc: mocker.patch.object(rpc, 'send_json', new_callable=lambda: test_send_json_1) unlinked_results = aiohttp_rpc.UnlinkedResults(data=[[1]]) assert await rpc.batch(( 'method_1', 'method_2', )) == [[1, 2, 1], unlinked_results] mocker.patch.object(rpc, 'send_json', new_callable=lambda: test_send_json_2) unlinked_results = aiohttp_rpc.UnlinkedResults(data=[[1], [1]]) assert await rpc.batch(( 'method_1', 'method_2', 'method_2', )) == [[1, 2, 1], unlinked_results, unlinked_results]
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.JsonRpcServer() 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_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.JsonRpcClient('/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' }, ]