38
38
},
39
39
}
40
40
41
+ TWENTY_MB = 20 * 1024 * 1024
42
+ SIZED_MSG_START = b'{"id": 0, "jsonrpc": "2.0", "result": "'
43
+ SIZED_MSG_END = b'"}\n ' b""
44
+
41
45
42
46
@pytest .fixture
43
47
def jsonrpc_ipc_pipe_path ():
@@ -61,53 +65,80 @@ def simple_ipc_server(jsonrpc_ipc_pipe_path):
61
65
serv .close ()
62
66
63
67
64
- @pytest .fixture
65
- def serve_empty_result (simple_ipc_server ):
68
+ def ipc_server_reply (simple_ipc_server , response_fn ):
66
69
def reply ():
67
70
connection , client_address = simple_ipc_server .accept ()
68
71
try :
69
72
connection .recv (1024 )
70
- connection .sendall (b'{"id": 0, "result": {}' )
71
- time .sleep (0.1 )
72
- connection .sendall (b"}" )
73
+ response_fn (connection )
73
74
except BrokenPipeError :
74
75
pass
75
76
finally :
76
- # Clean up the connection
77
77
connection .close ()
78
78
simple_ipc_server .close ()
79
79
80
80
thd = Thread (target = reply , daemon = True )
81
81
thd .start ()
82
-
83
- try :
84
- yield
85
- finally :
86
- thd .join ()
82
+ return thd
87
83
88
84
89
85
@pytest .fixture
90
- def serve_subscription_result (simple_ipc_server ):
91
- def reply ( ):
92
- connection , client_address = simple_ipc_server . accept ( )
86
+ def ipc_server_fixture (simple_ipc_server ):
87
+ def server_fixture ( response_fn ):
88
+ thread = ipc_server_reply ( simple_ipc_server , response_fn )
93
89
try :
94
- connection .recv (1024 )
95
- connection .sendall (
96
- b'{"jsonrpc": "2.0", "id": 0, "result": "0xf13f7073ddef66a8c1b0c9c9f0e543c3"}' # noqa: E501
97
- )
98
- connection .sendall (json .dumps (ETH_SUBSCRIBE_RESPONSE ).encode ("utf-8" ))
90
+ yield
99
91
finally :
100
- # Clean up the connection
101
- connection .close ()
102
- simple_ipc_server .close ()
92
+ thread .join ()
103
93
104
- thd = Thread (target = reply , daemon = True )
105
- thd .start ()
94
+ return server_fixture
106
95
107
- try :
108
- yield
109
- finally :
110
- thd .join ()
96
+
97
+ @pytest .fixture
98
+ def serve_empty_result (ipc_server_fixture ):
99
+ def response_fn (connection ):
100
+ connection .sendall (b'{"id": 0, "result": {}' )
101
+ time .sleep (0.1 )
102
+ connection .sendall (b"}\n " )
103
+
104
+ yield from ipc_server_fixture (response_fn )
105
+
106
+
107
+ @pytest .fixture
108
+ def serve_20mb_response (ipc_server_fixture ):
109
+ def response_fn (connection ):
110
+ connection .sendall (
111
+ SIZED_MSG_START
112
+ + (b"a" * (TWENTY_MB - len (SIZED_MSG_START ) - len (SIZED_MSG_END )))
113
+ + SIZED_MSG_END
114
+ )
115
+
116
+ yield from ipc_server_fixture (response_fn )
117
+
118
+
119
+ @pytest .fixture
120
+ def serve_larger_than_20mb_response (ipc_server_fixture ):
121
+ def response_fn (connection ):
122
+ connection .sendall (
123
+ SIZED_MSG_START
124
+ + (b"a" * (TWENTY_MB - len (SIZED_MSG_START ) - len (SIZED_MSG_END ) + 1024 ))
125
+ + SIZED_MSG_END
126
+ )
127
+
128
+ yield from ipc_server_fixture (response_fn )
129
+
130
+
131
+ @pytest .fixture
132
+ def serve_subscription_result (ipc_server_fixture ):
133
+ def response_fn (connection ):
134
+ connection .sendall (
135
+ b"{"
136
+ b'"jsonrpc": "2.0", "id": 0, "result": "0xf13f7073ddef66a8c1b0c9c9f0e543c3"'
137
+ b"}\n "
138
+ )
139
+ connection .sendall (json .dumps (ETH_SUBSCRIBE_RESPONSE ).encode ("utf-8" ))
140
+
141
+ yield from ipc_server_fixture (response_fn )
111
142
112
143
113
144
def test_ipc_tilde_in_path ():
@@ -226,7 +257,7 @@ async def test_async_iterator_pattern_exception_handling_for_requests(
226
257
exception_caught = False
227
258
async for w3 in AsyncWeb3 (AsyncIPCProvider (pathlib .Path (jsonrpc_ipc_pipe_path ))):
228
259
# patch the listener to raise `ConnectionClosed` on read
229
- w3 .provider ._reader .read = _raise_connection_closed
260
+ w3 .provider ._reader .readline = _raise_connection_closed
230
261
try :
231
262
await w3 .eth .block_number
232
263
except ConnectionClosed :
@@ -249,7 +280,7 @@ async def test_async_iterator_pattern_exception_handling_for_subscriptions(
249
280
exception_caught = False
250
281
async for w3 in AsyncWeb3 (AsyncIPCProvider (pathlib .Path (jsonrpc_ipc_pipe_path ))):
251
282
# patch the listener to raise `ConnectionClosed` on read
252
- w3 .provider ._reader .read = _raise_connection_closed
283
+ w3 .provider ._reader .readline = _raise_connection_closed
253
284
try :
254
285
async for _ in w3 .socket .process_subscriptions ():
255
286
# raises exception
@@ -264,3 +295,37 @@ async def test_async_iterator_pattern_exception_handling_for_subscriptions(
264
295
pytest .fail ("Expected `ConnectionClosed` exception." )
265
296
266
297
assert exception_caught
298
+
299
+
300
+ @pytest .mark .asyncio
301
+ async def test_async_ipc_reader_can_read_20mb_message (
302
+ jsonrpc_ipc_pipe_path , serve_20mb_response
303
+ ):
304
+ async with AsyncWeb3 (AsyncIPCProvider (pathlib .Path (jsonrpc_ipc_pipe_path ))) as w3 :
305
+ response = await w3 .provider .make_request ("method" , [])
306
+ assert len (response ["result" ]) == TWENTY_MB - len (SIZED_MSG_START ) - len (
307
+ SIZED_MSG_END
308
+ )
309
+
310
+
311
+ @pytest .mark .asyncio
312
+ async def test_async_ipc_reader_raises_on_msg_over_20mb (
313
+ jsonrpc_ipc_pipe_path , serve_larger_than_20mb_response
314
+ ):
315
+ with pytest .raises (ValueError ):
316
+ async with AsyncWeb3 (
317
+ AsyncIPCProvider (pathlib .Path (jsonrpc_ipc_pipe_path ))
318
+ ) as w3 :
319
+ await w3 .provider .make_request ("method" , [])
320
+
321
+
322
+ @pytest .mark .asyncio
323
+ async def test_async_ipc_read_buffer_limit_is_configurable (
324
+ jsonrpc_ipc_pipe_path , serve_larger_than_20mb_response
325
+ ):
326
+ async with AsyncWeb3 (
327
+ AsyncIPCProvider (
328
+ pathlib .Path (jsonrpc_ipc_pipe_path ), read_buffer_limit = TWENTY_MB + 1024
329
+ )
330
+ ) as w3 :
331
+ await w3 .provider .make_request ("method" , [])
0 commit comments