Passed
Pull Request — master (#5)
by Michael
05:44
created

tests.test_protocol_for_ws   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 313
Duplicated Lines 82.11 %

Importance

Changes 0
Metric Value
wmc 21
eloc 174
dl 257
loc 313
rs 10
c 0
b 0
f 0

8 Functions

Rating   Name   Duplication   Size   Complexity  
A test_rpc_call_of_non_existent_method() 16 16 3
A test_rpc_call_with_an_invalid_batch() 25 25 2
A test_rpc_call_with_invalid_json() 0 28 3
B test_rpc_call_with_invalid_batch() 31 31 2
A test_rpc_call_with_positional_parameters() 26 26 2
A test_rpc_call_with_named_parameters() 30 30 2
A test_rpc_call_with_an_empty_array() 32 32 3
A test_notification() 27 27 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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(rpc, '_handle_ws_message', side_effect=rpc._handle_ws_message)
142
        rpc.json_serialize = lambda x: x
143
        result = await rpc.send_json('{"jsonrpc": "2.0", "method": "foobar, "params": "bar", "baz]')
144
        assert result == (None, None,)
145
        await asyncio.wait_for(future, timeout=3)
146
        handle_ws_message.assert_called_once()
147
148
149 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...
150
    """
151
    --> []
152
    <-- {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
153
    """
154
155
    rpc_server = aiohttp_rpc.WsJsonRpcServer()
156
157
    client = await utils.make_ws_client(aiohttp_client, rpc_server)
158
159
    future = asyncio.Future()
160
161
    def unprocessed_json_response_handler(*, ws_connect, ws_msg, json_response):
162
        future.set_result(json_response)
163
        assert json_response == {
164
            'jsonrpc': '2.0', 'error': {'code': -32600, 'message': errors.InvalidRequest.message}, 'id': None,
165
        }
166
167
    async with aiohttp_rpc.WsJsonRpcClient(
168
            '/rpc',
169
            session=client,
170
            unprocessed_json_response_handler=unprocessed_json_response_handler,
171
    ) as rpc:
172
        handle_ws_message = mocker.patch.object(rpc, '_handle_ws_message', side_effect=rpc._handle_ws_message)
173
174
        with pytest.raises(errors.InvalidRequest):
175
            await rpc.batch([])
176
177
        handle_ws_message.assert_not_called()
178
        await rpc.send_json([])
179
        await asyncio.wait_for(future, timeout=3)
180
        handle_ws_message.assert_called_once()
181
182
183 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...
184
    """
185
    --> [1]
186
    <-- {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
187
    """
188
189
    rpc_server = aiohttp_rpc.WsJsonRpcServer()
190
    client = await utils.make_ws_client(aiohttp_client, rpc_server)
191
    future = asyncio.Future()
192
193
    def unprocessed_json_response_handler(*, ws_connect, ws_msg, json_response):
194
        future.set_result(json_response)
195
        assert json_response == {
196
            'jsonrpc': '2.0', 'error': {'code': -32600, 'message': 'Data must be a dict.'}, 'id': None,
197
        }
198
199
    async with aiohttp_rpc.WsJsonRpcClient(
200
            '/rpc',
201
            session=client,
202
            unprocessed_json_response_handler=unprocessed_json_response_handler,
203
    ) as rpc:
204
        handle_ws_message = mocker.patch.object(rpc, '_handle_ws_message', side_effect=rpc._handle_ws_message)
205
        await rpc.send_json([1])
206
        await asyncio.wait_for(future, timeout=3)
207
        handle_ws_message.assert_called_once()
208
209
210 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...
211
    """
212
    --> [1,2,3]
213
    <-- [
214
      {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
215
      {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
216
      {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
217
    ]
218
    """
219
220
    rpc_server = aiohttp_rpc.WsJsonRpcServer()
221
    client = await utils.make_ws_client(aiohttp_client, rpc_server)
222
    future = asyncio.Future()
223
224
    json_with_error = {
225
        'jsonrpc': '2.0', 'error': {'code': -32600, 'message': 'Data must be a dict or an list.'}, 'id': None,
226
    }
227
228
    def unprocessed_json_response_handler(*, ws_connect, ws_msg, json_response):
229
        future.set_result(json_response)
230
        assert json_response == [json_with_error, json_with_error, json_with_error]
231
232
    async with aiohttp_rpc.WsJsonRpcClient(
233
            '/rpc',
234
            session=client,
235
            unprocessed_json_response_handler=unprocessed_json_response_handler,
236
    ) as rpc:
237
        handle_ws_message = mocker.patch.object(rpc, '_handle_ws_message', side_effect=rpc._handle_ws_message)
238
        await rpc.send_json([1, 2, 3])
239
        await asyncio.wait_for(future, timeout=3)
240
        handle_ws_message.assert_called_once()
241
242
243 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...
244
    """
245
    --> [
246
            {"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"},
247
            {"jsonrpc": "2.0", "method": "notify_hello", "params": [7]},
248
            {"jsonrpc": "2.0", "method": "subtract", "params": [42,23], "id": "2"},
249
            {"foo": "boo"},
250
            {"jsonrpc": "2.0", "method": "foo.get", "params": {"name": "myself"}, "id": "5"},
251
            {"jsonrpc": "2.0", "method": "get_data", "id": "9"}
252
        ]
253
    <-- [
254
            {"jsonrpc": "2.0", "result": 7, "id": "1"},
255
            {"jsonrpc": "2.0", "result": 19, "id": "2"},
256
            {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
257
            {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "5"},
258
            {"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"}
259
        ]
260
    """
261
262
    def subtract(a, b):
263
        return a - b
264
265
    def notify_hello(a):
266
        return a
267
268
    def get_data():
269
        return ['hello', 5]
270
271
    def my_sum(*args):
272
        return sum(args)
273
274
    rpc_server = aiohttp_rpc.WsJsonRpcServer()
275
    rpc_server.add_method(subtract)
276
    rpc_server.add_method((aiohttp_rpc.JsonRpcMethod(prefix='', func=my_sum, custom_name='sum')))
277
    rpc_server.add_method(notify_hello)
278
    rpc_server.add_method(get_data)
279
280
    client = await utils.make_ws_client(aiohttp_client, rpc_server)
281
282
    called_methods = [
283
        aiohttp_rpc.CalledJsonRpcMethod(msg_id=1, name='sum', params=[1, 2, 4]),
284
        aiohttp_rpc.CalledJsonRpcMethod(name='notify_hello', params=[1, 2, 4], is_notification=True),
285
        aiohttp_rpc.CalledJsonRpcMethod(msg_id=2, name='subtract', params=[42, 23]),
286
        aiohttp_rpc.CalledJsonRpcMethod(msg_id=5, name='foo.get', params={'name': 'myself'}),
287
        aiohttp_rpc.CalledJsonRpcMethod(msg_id=9, name='get_data'),
288
    ]
289
290
    async with aiohttp_rpc.WsJsonRpcClient('/rpc', session=client) as rpc:
291
        assert await rpc.batch(called_methods) == [7, None, 19, errors.MethodNotFound(), ['hello', 5]]
292
        assert await rpc.batch(called_methods, save_order=False) == [7, 19, errors.MethodNotFound(), ['hello', 5]]
293
294
        result = await rpc.send_json([
295
            {'jsonrpc': '2.0', 'method': 'sum', 'params': [1, 2, 4], 'id': '1'},
296
            {'jsonrpc': '2.0', 'method': 'notify_hello', 'params': [7]},
297
            {'jsonrpc': '2.0', 'method': 'subtract', 'params': [42, 23], 'id': '2'},
298
            {'foo': 'boo'},
299
            {'jsonrpc': '2.0', 'method': 'foo.get', 'params': {'name': 'myself'}, 'id': '5'},
300
            {'jsonrpc': '2.0', 'method': 'get_data', 'id': '9'}
301
        ])
302
303
        assert result[0] == [
304
            {'jsonrpc': '2.0', 'result': 7, 'id': '1'},
305
            {'jsonrpc': '2.0', 'result': 19, 'id': '2'},
306
            {'jsonrpc': '2.0', 'error': {
307
                'code': -32600, 'message': 'A request must contain "method" and "jsonrpc".'
308
            }, 'id': None},
309
            {'jsonrpc': '2.0', 'error': {
310
                'code': -32601, 'message': 'The method does not exist / is not available.'
311
            }, 'id': '5'},
312
            {'jsonrpc': '2.0', 'result': ['hello', 5], 'id': '9'},
313
        ]
314