Testing interaction of WebSockets with TestClient imposes thread safety? #2038
-
Hi, I'd like to test the interaction between multiple WebSockes using the Below is a small example that shows what I'd like to do. A websocket is created and if a second one is created the first shall be killed. If I run this using Python 3.11 on macOS the program hangs. The expected output would be Should Exampleimport asyncio
import uvicorn
from starlette.testclient import TestClient
from starlette.websockets import WebSocket
lock = asyncio.Lock() # not thread-safe
current = None
async def run(websocket):
# removing this stops the hanging
async with asyncio.TaskGroup() as tg:
tg.create_task(websocket.receive())
async def app(scope, receive, send) -> None:
if scope["type"] != "websocket":
return
global current
done = asyncio.Event() # not thread-safe
websocket = WebSocket(scope, receive=receive, send=send)
await websocket.accept()
task = asyncio.create_task(run(websocket))
async with lock:
if current:
current[0].cancel()
await current[1].wait()
current = (task, done)
try:
await task
await websocket.close()
finally:
done.set()
# Works with uvicorn
# uvicorn.run(app, port=5001)
client = TestClient(app, backend="asyncio")
with client.websocket_connect("") as ws1, client.websocket_connect("") as ws2:
pass |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
After reading the source code, this seems to work: client = TestClient(app, backend="asyncio")
with anyio.from_thread.start_blocking_portal(**client.async_backend) as portal:
client.portal = portal
with client.websocket_connect("") as ws1, client.websocket_connect("") as ws2:
pass Feels a bit hacky. Maybe |
Beta Was this translation helpful? Give feedback.
-
This doesn't hang anymore on the latest Starlette. |
Beta Was this translation helpful? Give feedback.
This doesn't hang anymore on the latest Starlette.