9
9
import subprocess
10
10
import sys
11
11
import time
12
- from typing import AsyncIterator , Callable , NoReturn , Set
12
+ from typing import (
13
+ AsyncIterator ,
14
+ Awaitable ,
15
+ Callable ,
16
+ Coroutine ,
17
+ NoReturn ,
18
+ Optional ,
19
+ Set ,
20
+ Tuple ,
21
+ )
13
22
from unittest import mock
14
23
from uuid import uuid4
15
24
@@ -440,8 +449,10 @@ def test_run_app_https(patched_loop) -> None:
440
449
)
441
450
442
451
443
- def test_run_app_nondefault_host_port (patched_loop , aiohttp_unused_port ) -> None :
444
- port = aiohttp_unused_port ()
452
+ def test_run_app_nondefault_host_port (
453
+ patched_loop : asyncio .AbstractEventLoop , unused_port_socket : socket .socket
454
+ ) -> None :
455
+ port = unused_port_socket .getsockname ()[1 ]
445
456
host = "127.0.0.1"
446
457
447
458
app = web .Application ()
@@ -454,7 +465,24 @@ def test_run_app_nondefault_host_port(patched_loop, aiohttp_unused_port) -> None
454
465
)
455
466
456
467
457
- def test_run_app_multiple_hosts (patched_loop ) -> None :
468
+ def test_run_app_with_sock (
469
+ patched_loop : asyncio .AbstractEventLoop , unused_port_socket : socket .socket
470
+ ) -> None :
471
+ sock = unused_port_socket
472
+ app = web .Application ()
473
+ web .run_app (
474
+ app ,
475
+ sock = sock ,
476
+ print = stopper (patched_loop ),
477
+ loop = patched_loop ,
478
+ )
479
+
480
+ patched_loop .create_server .assert_called_with ( # type: ignore[attr-defined]
481
+ mock .ANY , sock = sock , ssl = None , backlog = 128
482
+ )
483
+
484
+
485
+ def test_run_app_multiple_hosts (patched_loop : asyncio .AbstractEventLoop ) -> None :
458
486
hosts = ("127.0.0.1" , "127.0.0.2" )
459
487
460
488
app = web .Application ()
@@ -931,8 +959,16 @@ async def stop(self, request: web.Request) -> web.Response:
931
959
asyncio .get_running_loop ().call_soon (self .raiser )
932
960
return web .Response ()
933
961
934
- def run_app (self , port : int , timeout : int , task , extra_test = None ) -> asyncio .Task :
962
+ def run_app (
963
+ self ,
964
+ sock : socket .socket ,
965
+ timeout : int ,
966
+ task : Callable [[], Coroutine [None , None , None ]],
967
+ extra_test : Optional [Callable [[ClientSession ], Awaitable [None ]]] = None ,
968
+ ) -> Tuple ["asyncio.Task[None]" , int ]:
935
969
num_connections = - 1
970
+ t = test_task = None
971
+ port = sock .getsockname ()[1 ]
936
972
937
973
class DictRecordClear (dict ):
938
974
def clear (self ):
@@ -956,15 +992,15 @@ async def test() -> None:
956
992
try :
957
993
with pytest .raises (asyncio .TimeoutError ):
958
994
async with sess .get (
959
- f"http://localhost :{ port } /" ,
995
+ f"http://127.0.0.1 :{ port } /" ,
960
996
timeout = ClientTimeout (total = 0.1 ),
961
997
):
962
998
pass
963
999
except ClientConnectorError :
964
1000
await asyncio .sleep (0.5 )
965
1001
else :
966
1002
break
967
- async with sess .get (f"http://localhost :{ port } /stop" ):
1003
+ async with sess .get (f"http://127.0.0.1 :{ port } /stop" ):
968
1004
pass
969
1005
970
1006
if extra_test :
@@ -989,50 +1025,46 @@ async def handler(request: web.Request) -> web.Response:
989
1025
app .router .add_get ("/stop" , self .stop )
990
1026
991
1027
with mock .patch ("aiohttp.web_app.Server" , ServerWithRecordClear ):
992
- web .run_app (app , port = port , shutdown_timeout = timeout )
1028
+ web .run_app (app , sock = sock , shutdown_timeout = timeout )
993
1029
assert test_task .exception () is None
994
1030
return t , num_connections
995
1031
996
- def test_shutdown_wait_for_handler (
997
- self , aiohttp_unused_port : Callable [[], int ]
998
- ) -> None :
999
- port = aiohttp_unused_port ()
1032
+ def test_shutdown_wait_for_handler (self , unused_port_socket : socket .socket ) -> None :
1033
+ sock = unused_port_socket
1000
1034
finished = False
1001
1035
1002
1036
async def task ():
1003
1037
nonlocal finished
1004
1038
await asyncio .sleep (2 )
1005
1039
finished = True
1006
1040
1007
- t , connection_count = self .run_app (port , 3 , task )
1041
+ t , connection_count = self .run_app (sock , 3 , task )
1008
1042
1009
1043
assert finished is True
1010
1044
assert t .done ()
1011
1045
assert not t .cancelled ()
1012
1046
assert connection_count == 0
1013
1047
1014
- def test_shutdown_timeout_handler (
1015
- self , aiohttp_unused_port : Callable [[], int ]
1016
- ) -> None :
1017
- port = aiohttp_unused_port ()
1048
+ def test_shutdown_timeout_handler (self , unused_port_socket : socket .socket ) -> None :
1049
+ sock = unused_port_socket
1018
1050
finished = False
1019
1051
1020
1052
async def task ():
1021
1053
nonlocal finished
1022
1054
await asyncio .sleep (2 )
1023
1055
finished = True
1024
1056
1025
- t , connection_count = self .run_app (port , 1 , task )
1057
+ t , connection_count = self .run_app (sock , 1 , task )
1026
1058
1027
1059
assert finished is False
1028
1060
assert t .done ()
1029
1061
assert t .cancelled ()
1030
1062
assert connection_count == 1
1031
1063
1032
1064
def test_shutdown_timeout_not_reached (
1033
- self , aiohttp_unused_port : Callable [[], int ]
1065
+ self , unused_port_socket : socket . socket
1034
1066
) -> None :
1035
- port = aiohttp_unused_port ()
1067
+ sock = unused_port_socket
1036
1068
finished = False
1037
1069
1038
1070
async def task ():
@@ -1041,7 +1073,8 @@ async def task():
1041
1073
finished = True
1042
1074
1043
1075
start_time = time .time ()
1044
- t , connection_count = self .run_app (port , 15 , task )
1076
+
1077
+ t , connection_count = self .run_app (sock , 15 , task )
1045
1078
1046
1079
assert finished is True
1047
1080
assert t .done ()
@@ -1050,9 +1083,10 @@ async def task():
1050
1083
assert time .time () - start_time < 10
1051
1084
1052
1085
def test_shutdown_new_conn_rejected (
1053
- self , aiohttp_unused_port : Callable [[], int ]
1086
+ self , unused_port_socket : socket . socket
1054
1087
) -> None :
1055
- port = aiohttp_unused_port ()
1088
+ sock = unused_port_socket
1089
+ port = sock .getsockname ()[1 ]
1056
1090
finished = False
1057
1091
1058
1092
async def task () -> None :
@@ -1066,33 +1100,34 @@ async def test(sess: ClientSession) -> None:
1066
1100
with pytest .raises (ClientConnectorError ):
1067
1101
# Use a new session to try and open a new connection.
1068
1102
async with ClientSession () as sess :
1069
- async with sess .get (f"http://localhost :{ port } /" ):
1103
+ async with sess .get (f"http://127.0.0.1 :{ port } /" ):
1070
1104
pass
1071
1105
assert finished is False
1072
1106
1073
- t , connection_count = self .run_app (port , 10 , task , test )
1107
+ t , connection_count = self .run_app (sock , 10 , task , test )
1074
1108
1075
1109
assert finished is True
1076
1110
assert t .done ()
1077
1111
assert connection_count == 0
1078
1112
1079
1113
def test_shutdown_pending_handler_responds (
1080
- self , aiohttp_unused_port : Callable [[], int ]
1114
+ self , unused_port_socket : socket . socket
1081
1115
) -> None :
1082
- port = aiohttp_unused_port ()
1116
+ sock = unused_port_socket
1117
+ port = sock .getsockname ()[1 ]
1083
1118
finished = False
1084
1119
1085
1120
async def test () -> None :
1086
- async def test_resp (sess ) :
1087
- async with sess .get (f"http://localhost :{ port } /" ) as resp :
1121
+ async def test_resp (sess : ClientSession ) -> None :
1122
+ async with sess .get (f"http://127.0.0.1 :{ port } /" ) as resp :
1088
1123
assert await resp .text () == "FOO"
1089
1124
1090
1125
await asyncio .sleep (1 )
1091
1126
async with ClientSession () as sess :
1092
1127
t = asyncio .create_task (test_resp (sess ))
1093
1128
await asyncio .sleep (1 )
1094
1129
# Handler is in-progress while we trigger server shutdown.
1095
- async with sess .get (f"http://localhost :{ port } /stop" ):
1130
+ async with sess .get (f"http://127.0.0.1 :{ port } /stop" ):
1096
1131
pass
1097
1132
1098
1133
assert finished is False
@@ -1117,19 +1152,22 @@ async def handler(request: web.Request) -> web.Response:
1117
1152
app .router .add_get ("/" , handler )
1118
1153
app .router .add_get ("/stop" , self .stop )
1119
1154
1120
- web .run_app (app , port = port , shutdown_timeout = 5 )
1155
+ web .run_app (app , sock = sock , shutdown_timeout = 5 )
1156
+ assert t is not None
1121
1157
assert t .exception () is None
1122
1158
assert finished is True
1123
1159
1124
1160
def test_shutdown_close_idle_keepalive (
1125
- self , aiohttp_unused_port : Callable [[], int ]
1161
+ self , unused_port_socket : socket . socket
1126
1162
) -> None :
1127
- port = aiohttp_unused_port ()
1163
+ sock = unused_port_socket
1164
+ port = sock .getsockname ()[1 ]
1165
+ t = None
1128
1166
1129
1167
async def test () -> None :
1130
1168
await asyncio .sleep (1 )
1131
1169
async with ClientSession () as sess :
1132
- async with sess .get (f"http://localhost :{ port } /stop" ):
1170
+ async with sess .get (f"http://127.0.0.1 :{ port } /stop" ):
1133
1171
pass
1134
1172
1135
1173
# Hold on to keep-alive connection.
@@ -1148,15 +1186,14 @@ async def run_test(app: web.Application) -> None:
1148
1186
app .cleanup_ctx .append (run_test )
1149
1187
app .router .add_get ("/stop" , self .stop )
1150
1188
1151
- web .run_app (app , port = port , shutdown_timeout = 10 )
1189
+ web .run_app (app , sock = sock , shutdown_timeout = 10 )
1152
1190
# If connection closed, then test() will be cancelled in cleanup_ctx.
1153
1191
# If not, then shutdown_timeout will allow it to sleep until complete.
1154
1192
assert t .cancelled ()
1155
1193
1156
- def test_shutdown_close_websockets (
1157
- self , aiohttp_unused_port : Callable [[], int ]
1158
- ) -> None :
1159
- port = aiohttp_unused_port ()
1194
+ def test_shutdown_close_websockets (self , unused_port_socket : socket .socket ) -> None :
1195
+ sock = unused_port_socket
1196
+ port = sock .getsockname ()[1 ]
1160
1197
WS = web .AppKey ("ws" , Set [web .WebSocketResponse ])
1161
1198
client_finished = server_finished = False
1162
1199
@@ -1177,8 +1214,8 @@ async def close_websockets(app: web.Application) -> None:
1177
1214
async def test () -> None :
1178
1215
await asyncio .sleep (1 )
1179
1216
async with ClientSession () as sess :
1180
- async with sess .ws_connect (f"http://localhost :{ port } /ws" ) as ws :
1181
- async with sess .get (f"http://localhost :{ port } /stop" ):
1217
+ async with sess .ws_connect (f"http://127.0.0.1 :{ port } /ws" ) as ws :
1218
+ async with sess .get (f"http://127.0.0.1 :{ port } /stop" ):
1182
1219
pass
1183
1220
1184
1221
async for msg in ws :
@@ -1203,22 +1240,23 @@ async def run_test(app: web.Application) -> None:
1203
1240
app .router .add_get ("/stop" , self .stop )
1204
1241
1205
1242
start = time .time ()
1206
- web .run_app (app , port = port , shutdown_timeout = 10 )
1243
+ web .run_app (app , sock = sock , shutdown_timeout = 10 )
1207
1244
assert time .time () - start < 5
1208
1245
assert client_finished
1209
1246
assert server_finished
1210
1247
1211
1248
def test_shutdown_handler_cancellation_suppressed (
1212
- self , aiohttp_unused_port : Callable [[], int ]
1249
+ self , unused_port_socket : socket . socket
1213
1250
) -> None :
1214
- port = aiohttp_unused_port ()
1251
+ sock = unused_port_socket
1252
+ port = sock .getsockname ()[1 ]
1215
1253
actions = []
1216
1254
1217
1255
async def test () -> None :
1218
1256
async def test_resp (sess ):
1219
1257
t = ClientTimeout (total = 0.4 )
1220
1258
with pytest .raises (asyncio .TimeoutError ):
1221
- async with sess .get (f"http://localhost :{ port } /" , timeout = t ) as resp :
1259
+ async with sess .get (f"http://127.0.0.1 :{ port } /" , timeout = t ) as resp :
1222
1260
assert await resp .text () == "FOO"
1223
1261
actions .append ("CANCELLED" )
1224
1262
@@ -1227,7 +1265,7 @@ async def test_resp(sess):
1227
1265
await asyncio .sleep (0.5 )
1228
1266
# Handler is in-progress while we trigger server shutdown.
1229
1267
actions .append ("PRESTOP" )
1230
- async with sess .get (f"http://localhost :{ port } /stop" ):
1268
+ async with sess .get (f"http://127.0.0.1 :{ port } /stop" ):
1231
1269
pass
1232
1270
1233
1271
actions .append ("STOPPING" )
@@ -1255,6 +1293,6 @@ async def handler(request: web.Request) -> web.Response:
1255
1293
app .router .add_get ("/" , handler )
1256
1294
app .router .add_get ("/stop" , self .stop )
1257
1295
1258
- web .run_app (app , port = port , shutdown_timeout = 2 , handler_cancellation = True )
1296
+ web .run_app (app , sock = sock , shutdown_timeout = 2 , handler_cancellation = True )
1259
1297
assert t .exception () is None
1260
1298
assert actions == ["CANCELLED" , "SUPPRESSED" , "PRESTOP" , "STOPPING" , "DONE" ]
0 commit comments