@@ -147,23 +147,35 @@ async def _replace_project(
147147 return data
148148
149149
150- async def _connect_websocket (
150+ @pytest .fixture
151+ async def create_socketio_connection (
151152 socketio_client_factory : Callable ,
152- check_connection : bool ,
153- client : TestClient ,
154- client_id : str ,
155- events : dict [str , Callable ] | None = None ,
156- ) -> socketio .AsyncClient | None :
157- try :
158- sio = await socketio_client_factory (client_id , client )
159- assert sio .sid
160- if events :
161- for event , handler in events .items ():
162- sio .on (event , handler = handler )
163- return sio
164- except SocketConnectionError :
165- if check_connection :
166- pytest .fail ("socket io connection should not fail" )
153+ ) -> AsyncIterator [Callable [..., Awaitable [socketio .AsyncClient | None ]]]:
154+ connected_sockets = []
155+
156+ async def _ (
157+ check_connection : bool ,
158+ client : TestClient ,
159+ client_id : str ,
160+ events : dict [str , Callable ] | None = None ,
161+ ) -> socketio .AsyncClient | None :
162+
163+ try :
164+ sio = await socketio_client_factory (client_id , client )
165+ assert sio .sid
166+ if events :
167+ for event , handler in events .items ():
168+ sio .on (event , handler = handler )
169+ connected_sockets .append (sio )
170+ return sio
171+ except SocketConnectionError :
172+ if check_connection :
173+ pytest .fail ("socket io connection should not fail" )
174+
175+ yield _
176+
177+ # cleanup
178+ await asyncio .gather (* (socket .disconnect () for socket in connected_sockets ))
167179
168180
169181async def _open_project (
@@ -1338,7 +1350,37 @@ def clean_redis_table(redis_client) -> None:
13381350
13391351
13401352@pytest .mark .parametrize (* standard_user_role_response ())
1341- async def test_open_shared_project_2_users_locked (
1353+ async def test_open_shared_project_multiple_users (
1354+ max_number_of_user_sessions : int ,
1355+ with_enabled_rtc_collaboration : None ,
1356+ client : TestClient ,
1357+ client_on_running_server_factory : Callable [[], TestClient ],
1358+ logged_user : dict ,
1359+ shared_project : dict ,
1360+ socketio_client_factory : Callable [
1361+ [str | None , TestClient | None ], Awaitable [socketio .AsyncClient ]
1362+ ],
1363+ client_session_id_factory : Callable [[], str ],
1364+ expected : ExpectedResponse ,
1365+ mocker : MockerFixture ,
1366+ create_socketio_connection : Callable [..., Awaitable [socketio .AsyncClient | None ]],
1367+ ):
1368+ mock_project_state_updated_handler = mocker .Mock ()
1369+
1370+ base_client = client
1371+ base_client_tab_id = client_session_id_factory ()
1372+ # 1. user 1 opens project
1373+ await create_socketio_connection (
1374+ True ,
1375+ base_client ,
1376+ base_client_tab_id ,
1377+ {SOCKET_IO_PROJECT_UPDATED_EVENT : mock_project_state_updated_handler },
1378+ )
1379+
1380+
1381+ @pytest .mark .parametrize (* standard_user_role_response ())
1382+ async def test_open_shared_project_2_users_locked_remove_once_rtc_collaboration_is_defaulted (
1383+ with_enabled_rtc_collaboration : None ,
13421384 client : TestClient ,
13431385 client_on_running_server_factory : Callable [[], TestClient ],
13441386 logged_user : dict ,
@@ -1355,6 +1397,7 @@ async def test_open_shared_project_2_users_locked(
13551397 mock_dynamic_scheduler_rabbitmq : None ,
13561398 mocked_notifications_plugin : dict [str , mock .Mock ],
13571399 exit_stack : contextlib .AsyncExitStack ,
1400+ create_socketio_connection : Callable [..., Awaitable [socketio .AsyncClient | None ]],
13581401):
13591402 # Use-case: user 1 opens a shared project, user 2 tries to open it as well
13601403 mock_project_state_updated_handler = mocker .Mock ()
@@ -1365,8 +1408,7 @@ async def test_open_shared_project_2_users_locked(
13651408 client_id2 = client_session_id_factory ()
13661409
13671410 # 1. user 1 opens project
1368- await _connect_websocket (
1369- socketio_client_factory ,
1411+ await create_socketio_connection (
13701412 user_role != UserRole .ANONYMOUS ,
13711413 client_1 ,
13721414 client_id1 ,
@@ -1426,8 +1468,7 @@ async def test_open_shared_project_2_users_locked(
14261468 enable_check = user_role != UserRole .ANONYMOUS ,
14271469 exit_stack = exit_stack ,
14281470 )
1429- await _connect_websocket (
1430- socketio_client_factory ,
1471+ await create_socketio_connection (
14311472 user_role != UserRole .ANONYMOUS ,
14321473 client_2 ,
14331474 client_id2 ,
@@ -1566,13 +1607,13 @@ async def test_open_shared_project_at_same_time(
15661607 mock_dynamic_scheduler_rabbitmq : None ,
15671608 mocked_notifications_plugin : dict [str , mock .Mock ],
15681609 exit_stack : contextlib .AsyncExitStack ,
1610+ create_socketio_connection : Callable [..., Awaitable [socketio .AsyncClient | None ]],
15691611):
15701612 NUMBER_OF_ADDITIONAL_CLIENTS = 10
15711613 # log client 1
15721614 client_1 = client
15731615 client_id1 = client_session_id_factory ()
1574- sio_1 = await _connect_websocket (
1575- socketio_client_factory ,
1616+ sio_1 = await create_socketio_connection (
15761617 user_role != UserRole .ANONYMOUS ,
15771618 client_1 ,
15781619 client_id1 ,
@@ -1590,8 +1631,7 @@ async def test_open_shared_project_at_same_time(
15901631 exit_stack = exit_stack ,
15911632 )
15921633 client_id = client_session_id_factory ()
1593- sio = await _connect_websocket (
1594- socketio_client_factory ,
1634+ sio = await create_socketio_connection (
15951635 user_role != UserRole .ANONYMOUS ,
15961636 new_client ,
15971637 client_id ,
@@ -1657,6 +1697,7 @@ async def test_opened_project_can_still_be_opened_after_refreshing_tab(
16571697 mock_catalog_api : dict [str , mock .Mock ],
16581698 clean_redis_table ,
16591699 mocked_notifications_plugin : dict [str , mock .Mock ],
1700+ create_socketio_connection : Callable [..., Awaitable [socketio .AsyncClient | None ]],
16601701):
16611702 """Simulating a refresh goes as follows:
16621703 The user opens a project, then hit the F5 refresh page.
@@ -1665,8 +1706,7 @@ async def test_opened_project_can_still_be_opened_after_refreshing_tab(
16651706 """
16661707
16671708 client_session_id = client_session_id_factory ()
1668- sio = await _connect_websocket (
1669- socketio_client_factory ,
1709+ sio = await create_socketio_connection (
16701710 user_role != UserRole .ANONYMOUS ,
16711711 client ,
16721712 client_session_id ,
@@ -1686,8 +1726,7 @@ async def test_opened_project_can_still_be_opened_after_refreshing_tab(
16861726 # give some time
16871727 await asyncio .sleep (1 )
16881728 # re-connect using the same client session id
1689- sio2 = await _connect_websocket (
1690- socketio_client_factory ,
1729+ sio2 = await create_socketio_connection (
16911730 user_role != UserRole .ANONYMOUS ,
16921731 client ,
16931732 client_session_id ,
0 commit comments