|
|
|
@@ -0,0 +1,216 @@
|
|
|
|
|
From cf51816a2f7cd7a23d3e1129fe9418a5fc85d8be Mon Sep 17 00:00:00 2001
|
|
|
|
|
From: Vytautas Liuolia <vytautas.liuolia@gmail.com>
|
|
|
|
|
Date: Mon, 11 Nov 2024 08:43:02 +0100
|
|
|
|
|
Subject: [PATCH] chore(tests/asgi): migrate to the new `websockets` async
|
|
|
|
|
client (#2406)
|
|
|
|
|
|
|
|
|
|
* chore(tests/asgi): migrate to the new `websockets` async client
|
|
|
|
|
|
|
|
|
|
* chore: update the unsupported WS protocol exception for Daphne/Hypercorn
|
|
|
|
|
---
|
|
|
|
|
requirements/tests | 2 +-
|
|
|
|
|
tests/asgi/test_asgi_servers.py | 67 +++++++++++++++++----------------
|
|
|
|
|
2 files changed, 35 insertions(+), 34 deletions(-)
|
|
|
|
|
|
|
|
|
|
diff --git a/requirements/tests b/requirements/tests
|
|
|
|
|
index ada7c3729..36825fd23 100644
|
|
|
|
|
--- a/requirements/tests
|
|
|
|
|
+++ b/requirements/tests
|
|
|
|
|
@@ -13,7 +13,7 @@ testtools; python_version < '3.10'
|
|
|
|
|
aiofiles
|
|
|
|
|
httpx
|
|
|
|
|
uvicorn >= 0.17.0
|
|
|
|
|
-websockets
|
|
|
|
|
+websockets >= 13.1
|
|
|
|
|
|
|
|
|
|
# Handler Specific
|
|
|
|
|
cbor2
|
|
|
|
|
diff --git a/tests/asgi/test_asgi_servers.py b/tests/asgi/test_asgi_servers.py
|
|
|
|
|
index eb35ac62d..044d46a38 100644
|
|
|
|
|
--- a/tests/asgi/test_asgi_servers.py
|
|
|
|
|
+++ b/tests/asgi/test_asgi_servers.py
|
|
|
|
|
@@ -24,6 +24,7 @@
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
import websockets
|
|
|
|
|
+ import websockets.asyncio.client
|
|
|
|
|
import websockets.exceptions
|
|
|
|
|
except ImportError:
|
|
|
|
|
websockets = None # type: ignore
|
|
|
|
|
@@ -232,9 +233,9 @@ async def test_hello(
|
|
|
|
|
if close_code:
|
|
|
|
|
extra_headers['X-Close-Code'] = str(close_code)
|
|
|
|
|
|
|
|
|
|
- async with websockets.connect(
|
|
|
|
|
+ async with websockets.asyncio.client.connect(
|
|
|
|
|
server_url_events_ws,
|
|
|
|
|
- extra_headers=extra_headers,
|
|
|
|
|
+ additional_headers=extra_headers,
|
|
|
|
|
) as ws:
|
|
|
|
|
got_message = False
|
|
|
|
|
|
|
|
|
|
@@ -273,22 +274,22 @@ async def test_rejected(self, explicit_close, close_code, server_url_events_ws):
|
|
|
|
|
if close_code:
|
|
|
|
|
extra_headers['X-Close-Code'] = str(close_code)
|
|
|
|
|
|
|
|
|
|
- with pytest.raises(websockets.exceptions.InvalidStatusCode) as exc_info:
|
|
|
|
|
- async with websockets.connect(
|
|
|
|
|
- server_url_events_ws, extra_headers=extra_headers
|
|
|
|
|
+ with pytest.raises(websockets.exceptions.InvalidStatus) as exc_info:
|
|
|
|
|
+ async with websockets.asyncio.client.connect(
|
|
|
|
|
+ server_url_events_ws, additional_headers=extra_headers
|
|
|
|
|
):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
- assert exc_info.value.status_code == 403
|
|
|
|
|
+ assert exc_info.value.response.status_code == 403
|
|
|
|
|
|
|
|
|
|
async def test_missing_responder(self, server_url_events_ws):
|
|
|
|
|
server_url_events_ws += '/404'
|
|
|
|
|
|
|
|
|
|
- with pytest.raises(websockets.exceptions.InvalidStatusCode) as exc_info:
|
|
|
|
|
- async with websockets.connect(server_url_events_ws):
|
|
|
|
|
+ with pytest.raises(websockets.exceptions.InvalidStatus) as exc_info:
|
|
|
|
|
+ async with websockets.asyncio.client.connect(server_url_events_ws):
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
- assert exc_info.value.status_code == 403
|
|
|
|
|
+ assert exc_info.value.response.status_code == 403
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
|
'subprotocol, expected',
|
|
|
|
|
@@ -301,9 +302,9 @@ async def test_select_subprotocol_known(
|
|
|
|
|
self, subprotocol, expected, server_url_events_ws
|
|
|
|
|
):
|
|
|
|
|
extra_headers = {'X-Subprotocol': subprotocol}
|
|
|
|
|
- async with websockets.connect(
|
|
|
|
|
+ async with websockets.asyncio.client.connect(
|
|
|
|
|
server_url_events_ws,
|
|
|
|
|
- extra_headers=extra_headers,
|
|
|
|
|
+ additional_headers=extra_headers,
|
|
|
|
|
subprotocols=['amqp', 'wamp'],
|
|
|
|
|
) as ws:
|
|
|
|
|
assert ws.subprotocol == expected
|
|
|
|
|
@@ -312,9 +313,9 @@ async def test_select_subprotocol_unknown(self, server_url_events_ws):
|
|
|
|
|
extra_headers = {'X-Subprotocol': 'xmpp'}
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
- async with websockets.connect(
|
|
|
|
|
+ async with websockets.asyncio.client.connect(
|
|
|
|
|
server_url_events_ws,
|
|
|
|
|
- extra_headers=extra_headers,
|
|
|
|
|
+ additional_headers=extra_headers,
|
|
|
|
|
subprotocols=['amqp', 'wamp'],
|
|
|
|
|
):
|
|
|
|
|
pass
|
|
|
|
|
@@ -329,8 +330,8 @@ async def test_select_subprotocol_unknown(self, server_url_events_ws):
|
|
|
|
|
except websockets.exceptions.NegotiationError as ex:
|
|
|
|
|
assert 'unsupported subprotocol: xmpp' in str(ex)
|
|
|
|
|
|
|
|
|
|
- # Daphne
|
|
|
|
|
- except websockets.exceptions.InvalidMessage:
|
|
|
|
|
+ # Daphne, Hypercorn
|
|
|
|
|
+ except EOFError:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
# NOTE(kgriffs): When executing this test under pytest with the -s
|
|
|
|
|
@@ -340,8 +341,8 @@ async def test_select_subprotocol_unknown(self, server_url_events_ws):
|
|
|
|
|
# but the usual ways of capturing stdout/stderr with pytest do
|
|
|
|
|
# not work.
|
|
|
|
|
async def test_disconnecting_client_early(self, server_url_events_ws):
|
|
|
|
|
- ws = await websockets.connect(
|
|
|
|
|
- server_url_events_ws, extra_headers={'X-Close': 'True'}
|
|
|
|
|
+ ws = await websockets.asyncio.client.connect(
|
|
|
|
|
+ server_url_events_ws, additional_headers={'X-Close': 'True'}
|
|
|
|
|
)
|
|
|
|
|
await asyncio.sleep(0.2)
|
|
|
|
|
|
|
|
|
|
@@ -361,8 +362,8 @@ async def test_disconnecting_client_early(self, server_url_events_ws):
|
|
|
|
|
async def test_send_before_accept(self, server_url_events_ws):
|
|
|
|
|
extra_headers = {'x-accept': 'skip'}
|
|
|
|
|
|
|
|
|
|
- async with websockets.connect(
|
|
|
|
|
- server_url_events_ws, extra_headers=extra_headers
|
|
|
|
|
+ async with websockets.asyncio.client.connect(
|
|
|
|
|
+ server_url_events_ws, additional_headers=extra_headers
|
|
|
|
|
) as ws:
|
|
|
|
|
message = await ws.recv()
|
|
|
|
|
assert message == 'OperationNotAllowed'
|
|
|
|
|
@@ -370,8 +371,8 @@ async def test_send_before_accept(self, server_url_events_ws):
|
|
|
|
|
async def test_recv_before_accept(self, server_url_events_ws):
|
|
|
|
|
extra_headers = {'x-accept': 'skip', 'x-command': 'recv'}
|
|
|
|
|
|
|
|
|
|
- async with websockets.connect(
|
|
|
|
|
- server_url_events_ws, extra_headers=extra_headers
|
|
|
|
|
+ async with websockets.asyncio.client.connect(
|
|
|
|
|
+ server_url_events_ws, additional_headers=extra_headers
|
|
|
|
|
) as ws:
|
|
|
|
|
message = await ws.recv()
|
|
|
|
|
assert message == 'OperationNotAllowed'
|
|
|
|
|
@@ -379,8 +380,8 @@ async def test_recv_before_accept(self, server_url_events_ws):
|
|
|
|
|
async def test_invalid_close_code(self, server_url_events_ws):
|
|
|
|
|
extra_headers = {'x-close': 'True', 'x-close-code': 42}
|
|
|
|
|
|
|
|
|
|
- async with websockets.connect(
|
|
|
|
|
- server_url_events_ws, extra_headers=extra_headers
|
|
|
|
|
+ async with websockets.asyncio.client.connect(
|
|
|
|
|
+ server_url_events_ws, additional_headers=extra_headers
|
|
|
|
|
) as ws:
|
|
|
|
|
start = time.time()
|
|
|
|
|
|
|
|
|
|
@@ -395,22 +396,22 @@ async def test_invalid_close_code(self, server_url_events_ws):
|
|
|
|
|
async def test_close_code_on_unhandled_error(self, server_url_events_ws):
|
|
|
|
|
extra_headers = {'x-raise-error': 'generic'}
|
|
|
|
|
|
|
|
|
|
- async with websockets.connect(
|
|
|
|
|
- server_url_events_ws, extra_headers=extra_headers
|
|
|
|
|
+ async with websockets.asyncio.client.connect(
|
|
|
|
|
+ server_url_events_ws, additional_headers=extra_headers
|
|
|
|
|
) as ws:
|
|
|
|
|
await ws.wait_closed()
|
|
|
|
|
|
|
|
|
|
- assert ws.close_code in {3011, 1011}
|
|
|
|
|
+ assert ws.protocol.close_code in {3011, 1011}
|
|
|
|
|
|
|
|
|
|
async def test_close_code_on_unhandled_http_error(self, server_url_events_ws):
|
|
|
|
|
extra_headers = {'x-raise-error': 'http'}
|
|
|
|
|
|
|
|
|
|
- async with websockets.connect(
|
|
|
|
|
- server_url_events_ws, extra_headers=extra_headers
|
|
|
|
|
+ async with websockets.asyncio.client.connect(
|
|
|
|
|
+ server_url_events_ws, additional_headers=extra_headers
|
|
|
|
|
) as ws:
|
|
|
|
|
await ws.wait_closed()
|
|
|
|
|
|
|
|
|
|
- assert ws.close_code == 3400
|
|
|
|
|
+ assert ws.protocol.close_code == 3400
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize('mismatch', ['send', 'recv'])
|
|
|
|
|
@pytest.mark.parametrize('mismatch_type', ['text', 'data'])
|
|
|
|
|
@@ -420,8 +421,8 @@ async def test_type_mismatch(self, mismatch, mismatch_type, server_url_events_ws
|
|
|
|
|
'X-Mismatch-Type': mismatch_type,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- async with websockets.connect(
|
|
|
|
|
- server_url_events_ws, extra_headers=extra_headers
|
|
|
|
|
+ async with websockets.asyncio.client.connect(
|
|
|
|
|
+ server_url_events_ws, additional_headers=extra_headers
|
|
|
|
|
) as ws:
|
|
|
|
|
if mismatch == 'recv':
|
|
|
|
|
if mismatch_type == 'text':
|
|
|
|
|
@@ -431,13 +432,13 @@ async def test_type_mismatch(self, mismatch, mismatch_type, server_url_events_ws
|
|
|
|
|
|
|
|
|
|
await ws.wait_closed()
|
|
|
|
|
|
|
|
|
|
- assert ws.close_code in {3011, 1011}
|
|
|
|
|
+ assert ws.protocol.close_code in {3011, 1011}
|
|
|
|
|
|
|
|
|
|
async def test_passing_path_params(self, server_base_url_ws):
|
|
|
|
|
expected_feed_id = '1ee7'
|
|
|
|
|
url = f'{server_base_url_ws}feeds/{expected_feed_id}'
|
|
|
|
|
|
|
|
|
|
- async with websockets.connect(url) as ws:
|
|
|
|
|
+ async with websockets.asyncio.client.connect(url) as ws:
|
|
|
|
|
feed_id = await ws.recv()
|
|
|
|
|
assert feed_id == expected_feed_id
|
|
|
|
|
|