From 937f80fbe917dabf4890bf9af1c93439d64f44d0d6dd75da65788d87bbf0c341 Mon Sep 17 00:00:00 2001 From: Matej Cepl Date: Tue, 25 Mar 2025 20:52:57 +0000 Subject: [PATCH] Accepting request 1256021 from home:mcalabkova:branches:devel:languages:python - Add websockets.patch to fix test failure OBS-URL: https://build.opensuse.org/request/show/1256021 OBS-URL: https://build.opensuse.org/package/show/devel:languages:python/python-falcon?expand=0&rev=63 --- python-falcon.changes | 5 + python-falcon.spec | 4 +- websockets.patch | 216 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 websockets.patch diff --git a/python-falcon.changes b/python-falcon.changes index 77e1a03..8e3d028 100644 --- a/python-falcon.changes +++ b/python-falcon.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Tue Mar 25 15:51:05 UTC 2025 - Markéta Machová + +- Add websockets.patch to fix test failure + ------------------------------------------------------------------- Thu Jan 9 11:57:38 UTC 2025 - Daniel Garcia diff --git a/python-falcon.spec b/python-falcon.spec index fb4040c..4c173ee 100644 --- a/python-falcon.spec +++ b/python-falcon.spec @@ -30,6 +30,8 @@ Summary: A web framework for building APIs and app backends License: Apache-2.0 URL: http://falconframework.org Source: https://files.pythonhosted.org/packages/source/f/falcon/falcon-%{version}.tar.gz +# PATCH-FIX-UPSTREAM https://github.com/falconry/falcon/pull/2406 chore(tests/asgi): migrate to the new websockets async client +Patch: websockets.patch BuildRequires: %{python_module PyYAML} BuildRequires: %{python_module Sphinx} BuildRequires: %{python_module base >= 3.8} @@ -56,7 +58,7 @@ BuildRequires: %{python_module testtools} %if 0%{?suse_version} >= 1550 BuildRequires: %{python_module httpx if (%python-base without python36-base)} BuildRequires: %{python_module uvicorn if (%python-base without python36-base)} -BuildRequires: %{python_module websockets if (%python-base without python36-base)} +BuildRequires: %{python_module websockets >= 13.1 if (%python-base without python36-base)} %endif %if %{with doc} BuildRequires: %{python_module pydata-sphinx-theme} diff --git a/websockets.patch b/websockets.patch new file mode 100644 index 0000000..c71261b --- /dev/null +++ b/websockets.patch @@ -0,0 +1,216 @@ +From cf51816a2f7cd7a23d3e1129fe9418a5fc85d8be Mon Sep 17 00:00:00 2001 +From: Vytautas Liuolia +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 +