2222import sqlalchemy as sa
2323from aiohttp import ClientResponse
2424from aiohttp .test_utils import TestClient , TestServer
25+ from common_library .json_serialization import json_dumps
2526from faker import Faker
2627from models_library .api_schemas_directorv2 .dynamic_services import DynamicServiceGet
2728from models_library .api_schemas_dynamic_scheduler .dynamic_services import (
3637 ProjectStateOutputSchema ,
3738)
3839from models_library .api_schemas_webserver .projects_nodes import NodeGet , NodeGetIdle
40+ from models_library .groups import GroupID
3941from models_library .projects import ProjectID
4042from models_library .projects_state import (
4143 ProjectRunningState ,
4850 ServiceResourcesDictHelpers ,
4951)
5052from models_library .utils .fastapi_encoders import jsonable_encoder
53+ from pydantic import TypeAdapter
5154from pytest_mock import MockerFixture
5255from pytest_simcore .helpers .assert_checks import assert_status
5356from pytest_simcore .helpers .logging_tools import log_context
5457from pytest_simcore .helpers .monkeypatch_envs import setenvs_from_dict
5558from pytest_simcore .helpers .typing_env import EnvVarsDict
56- from pytest_simcore .helpers .webserver_login import log_client_in
59+ from pytest_simcore .helpers .webserver_login import LoggedUser , log_client_in
5760from pytest_simcore .helpers .webserver_parametrizations import (
5861 ExpectedResponse ,
5962 standard_role_response ,
@@ -99,7 +102,11 @@ def with_enabled_rtc_collaboration(
99102) -> None :
100103 setenvs_from_dict (
101104 monkeypatch ,
102- {"RTC_MAX_NUMBER_OF_USERS" : f"{ max_number_of_user_sessions } " },
105+ {
106+ "WEBSERVER_REALTIME_COLLABORATION" : json_dumps (
107+ {"RTC_MAX_NUMBER_OF_USERS" : max_number_of_user_sessions }
108+ )
109+ },
103110 )
104111
105112
@@ -1385,6 +1392,7 @@ async def test_open_shared_project_multiple_users(
13851392 shared_project : dict ,
13861393 client_session_id_factory : Callable [[], str ],
13871394 expected : ExpectedResponse ,
1395+ exit_stack : contextlib .AsyncExitStack ,
13881396 create_socketio_connection : Callable [
13891397 [TestClient , str ], Awaitable [tuple [socketio .AsyncClient , _SocketHandlers ]]
13901398 ],
@@ -1399,20 +1407,17 @@ async def test_open_shared_project_multiple_users(
13991407 )
14001408
14011409 # current state is closed and unlocked
1402- expected_project_state = ProjectStateOutputSchema (
1410+ closed_project_state = ProjectStateOutputSchema (
14031411 share_state = ProjectShareStateOutputSchema (
14041412 locked = False , status = ProjectStatus .CLOSED , current_user_groupids = []
14051413 ),
14061414 state = ProjectRunningState (value = RunningState .NOT_STARTED ),
14071415 )
1408- await _state_project (
1409- base_client , shared_project , expected .ok , expected_project_state
1410- )
1416+ await _state_project (base_client , shared_project , expected .ok , closed_project_state )
14111417
14121418 # now user 1 opens the shared project
14131419 await _open_project (base_client , base_client_tab_id , shared_project , expected .ok )
1414-
1415- expected_project_state = expected_project_state .model_copy (
1420+ opened_project_state = closed_project_state .model_copy (
14161421 update = {
14171422 "share_state" : ProjectShareStateOutputSchema (
14181423 locked = False ,
@@ -1424,11 +1429,56 @@ async def test_open_shared_project_multiple_users(
14241429 await _assert_project_state_updated (
14251430 sio_base_handlers [SOCKET_IO_PROJECT_UPDATED_EVENT ],
14261431 shared_project ,
1427- [expected_project_state ] * 2 ,
1428- )
1429- await _state_project (
1430- base_client , shared_project , expected .ok , expected_project_state
1432+ [opened_project_state ] * 2 ,
14311433 )
1434+ await _state_project (base_client , shared_project , expected .ok , opened_project_state )
1435+
1436+ # now we create more users and open the same project until we reach the maximum number of user sessions
1437+ for _ in range (1 , max_number_of_user_sessions ):
1438+ client_i = client_on_running_server_factory ()
1439+ client_i_tab_id = client_session_id_factory ()
1440+
1441+ # user i logs in
1442+ user_i = await exit_stack .enter_async_context (
1443+ LoggedUser (client_i , {"role" : logged_user ["role" ]})
1444+ )
1445+
1446+ sio_i , sio_i_handlers = await create_socketio_connection (
1447+ client_i , client_i_tab_id
1448+ )
1449+
1450+ # user i opens the shared project
1451+ await _open_project (client_i , client_i_tab_id , shared_project , expected .ok )
1452+ opened_project_state = opened_project_state .model_copy (
1453+ update = {
1454+ "share_state" : ProjectShareStateOutputSchema (
1455+ locked = False ,
1456+ status = ProjectStatus .OPENED ,
1457+ current_user_groupids = [
1458+ * opened_project_state .share_state .current_user_groupids ,
1459+ TypeAdapter (GroupID ).validate_python (user_i ["primary_gid" ]),
1460+ ],
1461+ ),
1462+ }
1463+ )
1464+ await _assert_project_state_updated (
1465+ sio_i_handlers [SOCKET_IO_PROJECT_UPDATED_EVENT ],
1466+ shared_project ,
1467+ [opened_project_state ]
1468+ * 1 , # NOTE: only one call per user since they are part of the everyone group
1469+ )
1470+ await _assert_project_state_updated (
1471+ sio_base_handlers [SOCKET_IO_PROJECT_UPDATED_EVENT ],
1472+ shared_project ,
1473+ [opened_project_state ]
1474+ * 2 , # NOTE: 2 calls since base user is part of the primary group and the all group
1475+ )
1476+ await _state_project (
1477+ client_i , shared_project , expected .ok , opened_project_state
1478+ )
1479+ await _state_project (
1480+ base_client , shared_project , expected .ok , opened_project_state
1481+ )
14321482
14331483
14341484@pytest .mark .parametrize (* standard_user_role_response ())
0 commit comments