11"""Tests for WebSocket JWT authentication (issue #72)."""
22
3+ import contextlib
34import uuid
45from collections .abc import AsyncGenerator
56from datetime import datetime , timedelta , timezone
6- from unittest .mock import AsyncMock , MagicMock , patch
7+ from unittest .mock import MagicMock , patch
78
89import pytest
910import pytest_asyncio
@@ -110,6 +111,12 @@ async def _override_get_db() -> AsyncGenerator[AsyncSession, None]:
110111 yield db_session
111112
112113 application .dependency_overrides [get_db ] = _override_get_db
114+
115+ @contextlib .asynccontextmanager
116+ async def _noop_lifespan (app ): # type: ignore[no-untyped-def]
117+ yield
118+
119+ application .router .lifespan_context = _noop_lifespan
113120 return application
114121
115122
@@ -128,26 +135,20 @@ def refresh_token() -> str:
128135 return create_refresh_token (uuid .uuid4 ())
129136
130137
131- def _make_mock_redis ():
132- """Create a mock Redis whose listen() yields one test message then stops."""
133-
134- async def _listen ():
135- # Yield a real message so the handler sends it over the websocket
136- yield {"type" : "message" , "data" : b'{"event": "test"}' }
137-
138- mock_pubsub = MagicMock ()
139- mock_pubsub .subscribe = AsyncMock ()
140- mock_pubsub .unsubscribe = AsyncMock ()
141- mock_pubsub .aclose = AsyncMock ()
142- mock_pubsub .listen = _listen
138+ def _make_mock_event_bus ():
139+ """Create a mock event bus whose subscribe() yields one test message then stops."""
140+ import asyncio as _asyncio
141+ from contextlib import asynccontextmanager
143142
144- mock_redis = MagicMock ()
145- mock_redis .pubsub .return_value = mock_pubsub
146- mock_redis .close = AsyncMock ()
143+ @asynccontextmanager
144+ async def _subscribe (session_id ):
145+ queue : _asyncio .Queue [str ] = _asyncio .Queue ()
146+ await queue .put ('{"event": "test"}' )
147+ yield queue
147148
148- mock_redis_class = MagicMock ()
149- mock_redis_class . from_url . return_value = mock_redis
150- return mock_redis_class
149+ bus = MagicMock ()
150+ bus . subscribe = _subscribe
151+ return bus
151152
152153
153154# ---------------------------------------------------------------------------
@@ -190,7 +191,7 @@ def test_none_token_raises(self):
190191@pytest .mark .asyncio
191192class TestWsAuthQueryParam :
192193 async def test_valid_token_accepted (self , app , session_id , valid_token ):
193- with patch ("redis.asyncio.Redis " , _make_mock_redis ()):
194+ with patch ("codehive.api.ws.create_event_bus " , return_value = _make_mock_event_bus ()):
194195 with TestClient (app ) as client :
195196 with client .websocket_connect (
196197 f"/api/sessions/{ session_id } /ws?token={ valid_token } "
@@ -235,7 +236,7 @@ async def test_refresh_token_rejected(self, app, session_id, refresh_token):
235236@pytest .mark .asyncio
236237class TestWsAuthFirstMessage :
237238 async def test_valid_auth_message_accepted (self , app , session_id , valid_token ):
238- with patch ("redis.asyncio.Redis " , _make_mock_redis ()):
239+ with patch ("codehive.api.ws.create_event_bus " , return_value = _make_mock_event_bus ()):
239240 with TestClient (app ) as client :
240241 with client .websocket_connect (f"/api/sessions/{ session_id } /ws" ) as ws :
241242 ws .send_json ({"type" : "auth" , "token" : valid_token })
0 commit comments