Passed
Push — master ( 0d356b...652bd4 )
by Michael
11:41 queued 05:19
created

tests.test_protocol_for_ws.test_notification()   A

Complexity

Conditions 2

Size

Total Lines 27
Code Lines 16

Duplication

Lines 27
Ratio 100 %

Importance

Changes 0
Metric Value
eloc 16
dl 27
loc 27
rs 9.6
c 0
b 0
f 0
cc 2
nop 1
1
# https://www.jsonrpc.org/specification#examples
2
import asyncio
3
4
import pytest
5
6
import aiohttp_rpc
7
from aiohttp_rpc import errors
8
from tests import utils
9
10
11 View Code Duplication
async def test_rpc_call_with_positional_parameters(aiohttp_client):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
12
    """
13
    --> {"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1}
14
    <-- {"jsonrpc": "2.0", "result": 19, "id": 1}
15
16
    --> {"jsonrpc": "2.0", "method": "subtract", "params": [23, 42], "id": 2}
17
    <-- {"jsonrpc": "2.0", "result": -19, "id": 2}
18
    """
19
20
    def subtract(a, b):
21
        return a - b
22
23
    rpc_server = aiohttp_rpc.WsJsonRpcServer()
24
    rpc_server.add_method(subtract)
25
26
    client = await utils.make_ws_client(aiohttp_client, rpc_server)
27
28
    async with aiohttp_rpc.WsJsonRpcClient('/rpc', session=client) as rpc:
29
        assert await rpc.subtract(42, 23) == 19
30
        assert await rpc.subtract(23, 42) == -19
31
32
        result = await rpc.send_json({'jsonrpc': '2.0', 'method': 'subtract', 'params': [42, 23], 'id': 1})
33
        assert result[0] == {'jsonrpc': '2.0', 'result': 19, 'id': 1}
34
35
        result = await rpc.send_json({'jsonrpc': '2.0', 'method': 'subtract', 'params': [23, 42], 'id': 2})
36
        assert result[0] == {'jsonrpc': '2.0', 'result': -19, 'id': 2}
37
38
39 View Code Duplication
async def test_rpc_call_with_named_parameters(aiohttp_client):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
40
    """
41
    --> {"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id": 3}
42
    <-- {"jsonrpc": "2.0", "result": 19, "id": 3}
43
44
    --> {"jsonrpc": "2.0", "method": "subtract", "params": {"minuend": 42, "subtrahend": 23}, "id": 4}
45
    <-- {"jsonrpc": "2.0", "result": 19, "id": 4}
46
    """
47
48
    def subtract(*, subtrahend, minuend):
49
        return minuend - subtrahend
50
51
    rpc_server = aiohttp_rpc.WsJsonRpcServer()
52
    rpc_server.add_method(subtract)
53
54
    client = await utils.make_ws_client(aiohttp_client, rpc_server)
55
56
    async with aiohttp_rpc.WsJsonRpcClient('/rpc', session=client) as rpc:
57
        assert await rpc.subtract(subtrahend=23, minuend=42) == 19
58
        assert await rpc.subtract(minuend=42, subtrahend=23) == 19
59
60
        result = await rpc.send_json({
61
            'jsonrpc': '2.0', 'method': 'subtract', 'params': {"subtrahend": 23, "minuend": 42}, 'id': 3,
62
        })
63
        assert result[0] == {'jsonrpc': '2.0', 'result': 19, 'id': 3}
64
65
        result = await rpc.send_json({
66
            'jsonrpc': '2.0', 'method': 'subtract', 'params': {"minuend": 42, "subtrahend": 23}, 'id': 4
67
        })
68
        assert result[0] == {'jsonrpc': '2.0', 'result': 19, 'id': 4}
69
70
71 View Code Duplication
async def test_notification(aiohttp_client):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
72
    """
73
    --> {"jsonrpc": "2.0", "method": "update", "params": [1,2,3,4,5]}
74
    --> {"jsonrpc": "2.0", "method": "foobar"}
75
    """
76
77
    def update(*args):
78
        return args
79
80
    def foobar(*args):
81
        return 'ok'
82
83
    rpc_server = aiohttp_rpc.WsJsonRpcServer()
84
    rpc_server.add_method(update)
85
    rpc_server.add_method(foobar)
86
87
    client = await utils.make_ws_client(aiohttp_client, rpc_server)
88
89
    async with aiohttp_rpc.WsJsonRpcClient('/rpc', session=client) as rpc:
90
        assert await rpc.notify('update', subtrahend=23, minuend=42) is None
91
        assert await rpc.notify('foobar', minuend=42, subtrahend=23) is None
92
93
        result = await rpc.send_json({'jsonrpc': '2.0', 'method': 'update', 'params': [1, 2, 3, 4, 5]})
94
        assert result[0] is None
95
96
        result = await rpc.send_json({'jsonrpc': '2.0', 'method': 'foobar'})
97
        assert result[0] is None
98
99
100 View Code Duplication
async def test_rpc_call_of_non_existent_method(aiohttp_client):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
101
    """
102
    --> {"jsonrpc": "2.0", "method": "foobar", "id": "1"}
103
    <-- {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "1"}
104
    """
105
106
    rpc_server = aiohttp_rpc.WsJsonRpcServer()
107
    client = await utils.make_ws_client(aiohttp_client, rpc_server)
108
109
    async with aiohttp_rpc.WsJsonRpcClient('/rpc', session=client) as rpc:
110
        with pytest.raises(errors.MethodNotFound):
111
            assert await rpc.call('foobar', subtrahend=23, minuend=42)
112
113
        result = await rpc.send_json({'jsonrpc': '2.0', 'method': 'foobar', 'id': '1'})
114
        assert result[0] == {
115
            'jsonrpc': '2.0', 'error': {'code': -32601, 'message': errors.MethodNotFound.message}, 'id': '1',
116
        }
117
118
119
async def test_rpc_call_with_invalid_json(aiohttp_client, mocker):
120
    """
121
    --> {"jsonrpc": "2.0", "method": "foobar, "params": "bar", "baz]
122
    <-- {"jsonrpc": "2.0", "error": {"code": -32700, "message": "Parse error"}, "id": null}
123
    """
124
125
    rpc_server = aiohttp_rpc.WsJsonRpcServer()
126
127
    client = await utils.make_ws_client(aiohttp_client, rpc_server)
128
129
    future = asyncio.Future()
130
131
    def unprocessed_json_response_handler(*, ws_connect, ws_msg, json_response):
132
        future.set_result(json_response)
133
        del json_response['error']['message']
134
        assert json_response == {'jsonrpc': '2.0', 'error': {'code': -32700}, 'id': None}
135
136
    async with aiohttp_rpc.WsJsonRpcClient(
137
            '/rpc',
138
            session=client,
139
            unprocessed_json_response_handler=unprocessed_json_response_handler,
140
    ) as rpc:
141
        handle_ws_message = mocker.patch.object(
142
            rpc,
143
            '_handle_single_ws_message',
144
            side_effect=rpc._handle_single_ws_message,
145
        )
146
        rpc.json_serialize = lambda x: x
147
        result = await rpc.send_json('{"jsonrpc": "2.0", "method": "foobar, "params": "bar", "baz]')
148
        assert result == (None, None,)
149
        await asyncio.wait_for(future, timeout=3)
150
        handle_ws_message.assert_called_once()
151
152
153 View Code Duplication
async def test_rpc_call_with_an_empty_array(aiohttp_client, mocker):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
154
    """
155
    --> []
156
    <-- {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
157
    """
158
159
    rpc_server = aiohttp_rpc.WsJsonRpcServer()
160
161
    client = await utils.make_ws_client(aiohttp_client, rpc_server)
162
163
    future = asyncio.Future()
164
165
    def unprocessed_json_response_handler(*, ws_connect, ws_msg, json_response):
166
        future.set_result(json_response)
167
        assert json_response == {
168
            'jsonrpc': '2.0', 'error': {'code': -32600, 'message': errors.InvalidRequest.message}, 'id': None,
169
        }
170
171
    async with aiohttp_rpc.WsJsonRpcClient(
172
            '/rpc',
173
            session=client,
174
            unprocessed_json_response_handler=unprocessed_json_response_handler,
175
    ) as rpc:
176
        handle_ws_message = mocker.patch.object(
177
            rpc,
178
            '_handle_single_ws_message',
179
            side_effect=rpc._handle_single_ws_message,
180
        )
181
182
        with pytest.raises(errors.InvalidRequest):
183
            await rpc.batch([])
184
185
        handle_ws_message.assert_not_called()
186
        await rpc.send_json([])
187
        await asyncio.wait_for(future, timeout=3)
188
        handle_ws_message.assert_called_once()
189
190
191 View Code Duplication
async def test_rpc_call_with_an_invalid_batch(aiohttp_client, mocker):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
192
    """
193
    --> [1]
194
    <-- {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
195
    """
196
197
    rpc_server = aiohttp_rpc.WsJsonRpcServer()
198
    client = await utils.make_ws_client(aiohttp_client, rpc_server)
199
    future = asyncio.Future()
200
201
    def unprocessed_json_response_handler(*, ws_connect, ws_msg, json_response):
202
        future.set_result(json_response)
203
        assert json_response == {
204
            'jsonrpc': '2.0', 'error': {'code': -32600, 'message': 'Data must be a dict.'}, 'id': None,
205
        }
206
207
    async with aiohttp_rpc.WsJsonRpcClient(
208
            '/rpc',
209
            session=client,
210
            unprocessed_json_response_handler=unprocessed_json_response_handler,
211
    ) as rpc:
212
        handle_ws_message = mocker.patch.object(
213
            rpc,
214
            '_handle_single_ws_message',
215
            side_effect=rpc._handle_single_ws_message,
216
        )
217
        await rpc.send_json([1])
218
        await asyncio.wait_for(future, timeout=3)
219
        handle_ws_message.assert_called_once()
220
221
222 View Code Duplication
async def test_rpc_call_with_invalid_batch(aiohttp_client, mocker):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
223
    """
224
    --> [1,2,3]
225
    <-- [
226
      {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
227
      {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
228
      {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
229
    ]
230
    """
231
232
    rpc_server = aiohttp_rpc.WsJsonRpcServer()
233
    client = await utils.make_ws_client(aiohttp_client, rpc_server)
234
    future = asyncio.Future()
235
236
    json_with_error = {
237
        'jsonrpc': '2.0', 'error': {'code': -32600, 'message': 'Data must be a dict or an list.'}, 'id': None,
238
    }
239
240
    def unprocessed_json_response_handler(*, ws_connect, ws_msg, json_response):
241
        future.set_result(json_response)
242
        assert json_response == [json_with_error, json_with_error, json_with_error]
243
244
    async with aiohttp_rpc.WsJsonRpcClient(
245
            '/rpc',
246
            session=client,
247
            unprocessed_json_response_handler=unprocessed_json_response_handler,
248
    ) as rpc:
249
        handle_ws_message = mocker.patch.object(
250
            rpc,
251
            '_handle_single_ws_message',
252
            side_effect=rpc._handle_single_ws_message,
253
        )
254
        await rpc.send_json([1, 2, 3])
255
        await asyncio.wait_for(future, timeout=3)
256
        handle_ws_message.assert_called_once()
257
258
259 View Code Duplication
async def test_rpc_call_with_invalid_batch(aiohttp_client):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
260
    """
261
    --> [
262
            {"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"},
263
            {"jsonrpc": "2.0", "method": "notify_hello", "params": [7]},
264
            {"jsonrpc": "2.0", "method": "subtract", "params": [42,23], "id": "2"},
265
            {"foo": "boo"},
266
            {"jsonrpc": "2.0", "method": "foo.get", "params": {"name": "myself"}, "id": "5"},
267
            {"jsonrpc": "2.0", "method": "get_data", "id": "9"}
268
        ]
269
    <-- [
270
            {"jsonrpc": "2.0", "result": 7, "id": "1"},
271
            {"jsonrpc": "2.0", "result": 19, "id": "2"},
272
            {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
273
            {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "5"},
274
            {"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"}
275
        ]
276
    """
277
278
    def subtract(a, b):
279
        return a - b
280
281
    def notify_hello(a):
282
        return a
283
284
    def get_data():
285
        return ['hello', 5]
286
287
    def my_sum(*args):
288
        return sum(args)
289
290
    rpc_server = aiohttp_rpc.WsJsonRpcServer()
291
    rpc_server.add_method(subtract)
292
    rpc_server.add_method((aiohttp_rpc.JsonRpcMethod(prefix='', func=my_sum, custom_name='sum')))
293
    rpc_server.add_method(notify_hello)
294
    rpc_server.add_method(get_data)
295
296
    client = await utils.make_ws_client(aiohttp_client, rpc_server)
297
298
    called_methods = [
299
        aiohttp_rpc.JsonRpcRequest(id=1, method_name='sum', params=[1, 2, 4]),
300
        aiohttp_rpc.JsonRpcRequest(method_name='notify_hello', params=[1, 2, 4]),
301
        aiohttp_rpc.JsonRpcRequest(id=2, method_name='subtract', params=[42, 23]),
302
        aiohttp_rpc.JsonRpcRequest(id=5, method_name='foo.get', params={'name': 'myself'}),
303
        aiohttp_rpc.JsonRpcRequest(id=9, method_name='get_data'),
304
    ]
305
306
    async with aiohttp_rpc.WsJsonRpcClient('/rpc', session=client) as rpc:
307
        assert await rpc.batch(called_methods) == [7, None, 19, errors.MethodNotFound(), ['hello', 5]]
308
        assert await rpc.batch(called_methods, save_order=False) == [7, 19, errors.MethodNotFound(), ['hello', 5]]
309
310
        result = await rpc.send_json([
311
            {'jsonrpc': '2.0', 'method': 'sum', 'params': [1, 2, 4], 'id': '1'},
312
            {'jsonrpc': '2.0', 'method': 'notify_hello', 'params': [7]},
313
            {'jsonrpc': '2.0', 'method': 'subtract', 'params': [42, 23], 'id': '2'},
314
            {'foo': 'boo'},
315
            {'jsonrpc': '2.0', 'method': 'foo.get', 'params': {'name': 'myself'}, 'id': '5'},
316
            {'jsonrpc': '2.0', 'method': 'get_data', 'id': '9'}
317
        ])
318
319
        assert result[0] == [
320
            {'jsonrpc': '2.0', 'result': 7, 'id': '1'},
321
            {'jsonrpc': '2.0', 'result': 19, 'id': '2'},
322
            {'jsonrpc': '2.0', 'error': {
323
                'code': -32600, 'message': 'A request must contain "method" and "jsonrpc".'
324
            }, 'id': None},
325
            {'jsonrpc': '2.0', 'error': {
326
                'code': -32601, 'message': 'The method does not exist / is not available.'
327
            }, 'id': '5'},
328
            {'jsonrpc': '2.0', 'result': ['hello', 5], 'id': '9'},
329
        ]
330