200 lines
5.6 KiB
Python
200 lines
5.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
# type: ignore
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from unittest import mock
|
|
|
|
from bthlabs_jsonrpc_core import exceptions, serializer
|
|
import pytest
|
|
|
|
from bthlabs_jsonrpc_aiohttp import executor
|
|
from tests.fixtures import AsyncJSONCodec
|
|
|
|
|
|
@pytest.fixture
|
|
def fake_can_call() -> mock.Mock:
|
|
result = mock.AsyncMock()
|
|
result.return_value = True
|
|
|
|
return result
|
|
|
|
|
|
def test_init(fake_request: mock.Mock, fake_can_call: mock.Mock):
|
|
# When
|
|
result = executor.AioHttpExecutor(fake_request, fake_can_call)
|
|
|
|
# Then
|
|
assert result.request == fake_request
|
|
assert result.can_call == fake_can_call
|
|
|
|
|
|
async def test_list_methods(fake_request: mock.Mock, fake_can_call: mock.Mock):
|
|
# Given
|
|
the_executor = executor.AioHttpExecutor(fake_request, fake_can_call)
|
|
|
|
# When
|
|
result = await the_executor.list_methods()
|
|
|
|
# Then
|
|
assert result == ['system.list_methods']
|
|
|
|
|
|
async def test_deserialize_data(fake_request: mock.Mock,
|
|
fake_can_call: mock.Mock):
|
|
# Given
|
|
fake_request.text.return_value = '"spam"'
|
|
|
|
the_executor = executor.AioHttpExecutor(fake_request, fake_can_call)
|
|
|
|
# When
|
|
result = await the_executor.deserialize_data(fake_request)
|
|
|
|
# Then
|
|
assert result == 'spam'
|
|
|
|
|
|
async def test_deserialize_data_async_codec_decode(fake_request: mock.Mock,
|
|
async_json_codec: AsyncJSONCodec,
|
|
fake_can_call: mock.Mock):
|
|
# Given
|
|
fake_request.text.return_value = '"spam"'
|
|
|
|
the_executor = executor.AioHttpExecutor(
|
|
fake_request, fake_can_call, codec=async_json_codec,
|
|
)
|
|
|
|
# When
|
|
result = await the_executor.deserialize_data(fake_request)
|
|
|
|
# Then
|
|
assert result == 'spam'
|
|
|
|
|
|
async def test_deserialize_data_error(fake_request: mock.Mock,
|
|
fake_can_call: mock.Mock):
|
|
# Given
|
|
error = RuntimeError('I HAZ FAIL')
|
|
fake_request.text.side_effect = error
|
|
|
|
the_executor = executor.AioHttpExecutor(fake_request, fake_can_call)
|
|
|
|
# When
|
|
try:
|
|
_ = await the_executor.deserialize_data(fake_request)
|
|
except Exception as exception:
|
|
assert isinstance(exception, exceptions.JSONRPCParseError)
|
|
assert exception.__cause__ == error
|
|
else:
|
|
assert False, 'No exception raised?'
|
|
|
|
|
|
def test_enrich_args(fake_request: mock.Mock, fake_can_call: mock.Mock):
|
|
# Given
|
|
the_executor = executor.AioHttpExecutor(fake_request, fake_can_call)
|
|
|
|
# When
|
|
result = the_executor.enrich_args(['spam'])
|
|
|
|
# Then
|
|
assert result == [fake_request, 'spam']
|
|
|
|
|
|
async def test_before_call(fake_request: mock.Mock, fake_can_call: mock.Mock):
|
|
# Given
|
|
the_executor = executor.AioHttpExecutor(fake_request, fake_can_call)
|
|
|
|
# When
|
|
await the_executor.before_call('test', ['spam'], {'spam': True})
|
|
|
|
# Then
|
|
fake_can_call.assert_called_with(
|
|
fake_request, 'test', ['spam'], {'spam': True},
|
|
)
|
|
|
|
|
|
async def test_before_call_access_denied(fake_request: mock.Mock,
|
|
fake_can_call: mock.Mock):
|
|
# Given
|
|
fake_can_call.return_value = False
|
|
|
|
the_executor = executor.AioHttpExecutor(fake_request, fake_can_call)
|
|
|
|
# When
|
|
try:
|
|
await the_executor.before_call('test', ['spam'], {'spam': True})
|
|
except Exception as exception:
|
|
assert isinstance(exception, exceptions.JSONRPCAccessDeniedError)
|
|
else:
|
|
assert False, 'No exception raised?'
|
|
|
|
|
|
@mock.patch('bthlabs_jsonrpc_core.registry.MethodRegistry.shared_registry')
|
|
async def test_execute(mock_shared_registry: mock.Mock,
|
|
fake_request: mock.Mock,
|
|
fake_can_call: mock.Mock):
|
|
# Given
|
|
fake_method_registry = mock.Mock()
|
|
fake_method_registry.get_handler.return_value = None
|
|
fake_method_registry.get_methods.return_value = []
|
|
mock_shared_registry.return_value = fake_method_registry
|
|
|
|
batch = [
|
|
{
|
|
'jsonrpc': '2.0',
|
|
'id': 'call_1',
|
|
'method': 'system.list_methods',
|
|
'params': ['spam'],
|
|
},
|
|
{
|
|
'jsonrpc': '2.0',
|
|
'id': 'call_2',
|
|
'method': 'idontexist',
|
|
},
|
|
{
|
|
'jsonrpc': '2.0',
|
|
'method': 'system.list_methods',
|
|
'params': {'spam': True},
|
|
},
|
|
]
|
|
|
|
fake_request.text.return_value = json.dumps(batch)
|
|
|
|
the_executor = executor.AioHttpExecutor(fake_request, fake_can_call)
|
|
|
|
with mock.patch.object(the_executor, 'before_call') as mock_before_call:
|
|
# When
|
|
result = await the_executor.execute()
|
|
|
|
# Then
|
|
assert isinstance(result, serializer.JSONRPCSerializer)
|
|
|
|
expected_result_data = [
|
|
{
|
|
'jsonrpc': '2.0',
|
|
'id': 'call_1',
|
|
'result': ['system.list_methods'],
|
|
},
|
|
{
|
|
'jsonrpc': '2.0',
|
|
'id': 'call_2',
|
|
'error': {
|
|
'code': exceptions.JSONRPCMethodNotFoundError.ERROR_CODE,
|
|
'message': exceptions.JSONRPCMethodNotFoundError.ERROR_MESSAGE,
|
|
},
|
|
},
|
|
]
|
|
assert result.data == expected_result_data
|
|
|
|
fake_method_registry.get_handler.assert_called_with(
|
|
'jsonrpc', 'idontexist',
|
|
)
|
|
|
|
assert mock_before_call.call_count == 2
|
|
mock_before_call.assert_any_call(
|
|
'system.list_methods', [fake_request, 'spam'], {},
|
|
)
|
|
mock_before_call.assert_any_call(
|
|
'system.list_methods', [fake_request], {'spam': True},
|
|
)
|