async def test_clt_batch_empty(): reg = RpcRegistry() clt = get_clt(reg) result = await clt.exec_batch() assert result == ()
async def test_rpc_response_header(loop, unused_tcp_port): reg = RpcRegistry() @reg.method() def method1(): set_reponse_header('A', 'B') set_reponse_header('C', 'D') set_response_cookie('E', 'F') del_response_cookie('G') return 'ok' async with runapp(unused_tcp_port, JsonRpcHttpHandler(reg, JsonRpcHttpHandlerConfig())): async with ClientSession() as sess: resp = await sess.request( 'POST', 'http://127.0.0.1:%s/' % unused_tcp_port, json={ 'method': 'method1', 'jsonrpc': '2.0', 'id': 1 }, ) assert resp.headers['A'] == 'B' assert resp.headers['C'] == 'D' assert resp.cookies['E'].value == 'F' assert resp.cookies['G'].value == ''
async def test_rpc_client_arg_as_bytes(loop, unused_tcp_port): reg = RpcRegistry() some_data = os.urandom(100) @reg.method() def compare_bytes(b_data: bytes) -> bool: return some_data == b_data class TestRpcClientBytesArg(JsonRpcHttpClient): def compare_bytes( self, b_data: bytes, timeout: Optional[float] = None, ) -> Awaitable[bool]: return self.exec( "compare_bytes", {'b_data': b_data}, timeout=timeout, ) async with runapp(unused_tcp_port, JsonRpcHttpHandler(reg, JsonRpcHttpHandlerConfig())) as app: clt = TestRpcClientBytesArg( JsonRpcHttpClientConfig(url='http://%s:%s/' % (app.cfg.srv.host, app.cfg.srv.port))) app.add('clt_ba', clt) await clt.prepare() await clt.start() result = await clt.compare_bytes(some_data) assert result is True
async def test_rpc_response_header(loop, unused_tcp_port): # type: ignore reg = RpcRegistry() @reg.method() def method1(a: Any): # type: ignore set_reponse_header('A', 'B') set_reponse_header('C', 'D') set_response_cookie('E', 'F') del_response_cookie('G') return {'method1': 'ok'} async with runapp(unused_tcp_port, RestRpcHttpHandler(reg, RestRpcHttpHandlerConfig())): async with ClientSession() as sess: resp = await sess.request( 'POST', 'http://127.0.0.1:%s/method1' % unused_tcp_port, json={'a': 'anything'}, ) assert resp.headers['A'] == 'B' assert resp.headers['C'] == 'D' assert resp.cookies['E'].value == 'F' assert resp.cookies['G'].value == '' resp_2 = await sess.request( 'OPTIONS', 'http://127.0.0.1:%s/method1' % unused_tcp_port) assert (resp_2.headers['Access-Control-Allow-Methods'] == 'OPTIONS, POST') assert resp_2.status == 200 assert resp_2.reason == 'OK'
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_rpc_error(loop, unused_tcp_port): class MyError(JsonRpcError): jsonrpc_error_code = 100 message = 'Err' reg = RpcRegistry() @reg.method() def method1(): raise MyError(data={'a': 1}) async with runapp(unused_tcp_port, JsonRpcHttpHandler(reg, JsonRpcHttpHandlerConfig())): async with ClientSession() as sess: resp = await sess.request( 'POST', 'http://127.0.0.1:%s/' % unused_tcp_port, json={ 'method': 'method1', 'jsonrpc': '2.0', 'id': 1 }, ) result = await resp.json() assert result == { 'id': 1, 'jsonrpc': '2.0', 'error': { 'code': 100, 'message': 'Err', 'data': { 'a': 1 } }, }
async def test_rpc_error(loop, unused_tcp_port): # type: ignore class MyError(RestRpcError): code = 1000 message = 'Err' class MyError409(RestRpcError): code = 409 message = 'Err' reg = RpcRegistry() @reg.method() def method1(a: Any): # type: ignore raise MyError(data={'a': 1}) @reg.method() def method2(a: Any): # type: ignore raise MyError409(data={'b': 2}) async with runapp(unused_tcp_port, RestRpcHttpHandler(reg, RestRpcHttpHandlerConfig())): async with ClientSession() as sess: resp = await sess.request( 'POST', 'http://127.0.0.1:%s/method1/' % unused_tcp_port, json={'a': 'anything'}, ) result = await resp.json() assert resp.status == 200 assert resp.reason == 'OK' assert result == { 'error': { 'code': 1000, 'message': 'Err', 'data': { 'a': 1 } }, } resp_2 = await sess.request( 'POST', 'http://127.0.0.1:%s/method2/' % unused_tcp_port, json={'a': 'anything'}, ) result_2 = await resp_2.json() assert result_2 == { 'error': { 'code': 409, 'message': 'Err', 'data': { 'b': 2 } }, } assert resp_2.status == 409 assert resp_2.reason == 'Conflict'
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 test_error() -> None: reg = RpcRegistry() @reg.method() async def echo(text: str) -> str: raise Exception('Ex') ex = RestRpcExecutor(reg, get_app()) res, status = await ex.exec(b'{"text": "123"}', method_name='echo') assert json.loads(res) == {'error': {'code': 500, 'message': 'Ex'}} assert status == 500
async def test_clt_single_notification(): reg = RpcRegistry() @reg.method() async def sum(a: int, b: int) -> int: return a + b clt = get_clt(reg) result = await clt.exec('sum', [1, 2], one_way=True) assert result is None
async def test_clt() -> None: reg = RpcRegistry() @reg.method() async def sum(a: int, b: int) -> Dict[str, int]: return {'sum': a + b} clt = get_clt(reg) result = await clt.exec('sum', {'a': 1, 'b': 2}) assert result == {'sum': 3}
async def test_clt_single(): reg = RpcRegistry() @reg.method() async def sum(a: int, b: int) -> int: return a + b clt = get_clt(reg) result = await clt.exec('sum', [1, 2]) assert result == 3
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() -> None: reg = RpcRegistry() ex = RestRpcExecutor(reg, get_app()) res, status = await ex.exec(b'{"text": "123"}', method_name='echo') assert json.loads(res) == { 'error': { 'code': 404, 'message': 'Method not found' } } assert status == 404
async def test_success_by_name() -> None: reg = RpcRegistry() @reg.method() async def echo(text: str) -> Dict[str, str]: return {'echo': text} ex = RestRpcExecutor(reg, get_app()) res, status = await ex.exec(b' {"text": "123"}', method_name='echo') assert json.loads(res) == {'echo': '123'} assert status == 200
async def test_rpc(loop, rabbitmq_url): reg = RpcRegistry() @reg.method() def method1(val: str) -> str: return 'ok %s' % val async with runapp(rabbitmq_url, reg) as app: with app.logger.span_new(): val = 123 res = await app.clt.exec('method1', {'val': val}, timeout=2) assert res == 'ok %s' % val
async def test_rpc_client(loop, unused_tcp_port): reg = RpcRegistry() @reg.method() def method1(): return 'ok' async with runapp(unused_tcp_port, JsonRpcHttpHandler(reg, JsonRpcHttpHandlerConfig())) as app: result = await app.clt.exec('method1') assert result == 'ok'
async def test_success_by_pos_default() -> None: reg = RpcRegistry() @reg.method() async def sum(a: int, b: int, c: int = 3) -> Dict[str, int]: return {'sum': a + b + c} ex = RestRpcExecutor(reg, get_app()) res, status = await ex.exec(b'{"a": 1,"b": 2}', method_name='sum') assert json.loads(res) == {"sum": 6} assert status == 200
async def test_rpc_client(loop, unused_tcp_port): # type: ignore reg = RpcRegistry() @reg.method() def method1(a: Any): # type: ignore return {'method1': 'ok'} async with runapp(unused_tcp_port, RestRpcHttpHandler(reg, RestRpcHttpHandlerConfig())) as app: result = await app.clt.exec('method1', {'a': 'anything'}) assert result == {'method1': 'ok'}
async def test_clt_err_method() -> None: reg = RpcRegistry() @reg.method() async def sum(a: int, b: int) -> Dict[str, int]: return {'sum': a + b} clt = get_clt(reg) with pytest.raises(RestRpcError) as exc_info: await clt.exec('sum2', {'a': 1, 'b': 2}) assert exc_info.value.code == 404 assert exc_info.value.message == 'Method not found'
async def test_clt_batch(): reg = RpcRegistry() @reg.method() async def sum(a: int, b: int) -> int: return a + b clt = get_clt(reg) result = await clt.exec_batch( clt.exec('sum', [1, 2]), clt.exec('sum', [3, 4]) ) assert result == (3, 7)
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_clt_batch_notification(): reg = RpcRegistry() @reg.method() async def sum(a: int, b: int) -> int: return a + b clt = get_clt(reg) result = await clt.exec_batch( clt.exec('sum', [1, 2], one_way=True), clt.exec('sum', [3, 4], one_way=True), ) assert result == (None, None)
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_rpc_batch(loop, rabbitmq_url): reg = RpcRegistry() @reg.method() def method1(val: str) -> str: return 'ok %s' % val async with runapp(rabbitmq_url, reg) as app: with app.logger.span_new(): res1, res2 = await app.clt.exec_batch( app.clt.exec('method1', {'val': 123}), app.clt.exec('method1', {'val': 234}), ) assert res1 == 'ok 123'
async def test_rpc_with_any_subpath(loop, unused_tcp_port): # type: ignore reg = RpcRegistry() @reg.method() def method1(a: Any): # type: ignore return {'status': 'ok'} async with runapp_with_any_subpath( unused_tcp_port, RestRpcHttpHandler(reg, RestRpcHttpHandlerConfig(path='/api/v1/')), ): async with ClientSession() as sess: resp = await sess.request( 'POST', 'http://127.0.0.1:%s/api/v1/method1/' % unused_tcp_port, json={'a': 'anything'}, ) result = await resp.json() assert resp.status == 200 assert resp.reason == 'OK' assert resp.headers.get('Content-Type', None) == 'application/json' assert result == {'status': 'ok'} resp_2 = await sess.request( 'POST', 'http://127.0.0.1:%s/api/v1/method1' % unused_tcp_port, json={'a': 'anything'}, ) result_2 = await resp_2.json() assert result_2 == {'status': 'ok'} resp_3 = await sess.request( 'POST', 'http://127.0.0.1:%s/api/v1/nonexistentmethod' % unused_tcp_port, json={'a': 'anything'}, ) assert resp_3.status == 404 assert resp_3.reason == 'Not Found' resp_4 = await sess.request( 'POST', 'http://127.0.0.1:%s/api/v0/method1' % unused_tcp_port, json={'a': 'anything'}, ) assert resp_4.status == 404 assert resp_4.reason == 'Not Found'
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', }