fixup! fixup! wip adapt lobby to be functional in an iframe

This commit is contained in:
lebaudantoine
2026-08-17 12:30:27 +02:00
parent 087b0cb06e
commit aefaa0ce98
3 changed files with 86 additions and 67 deletions
+6 -9
View File
@@ -145,12 +145,7 @@ class LobbyService:
user_role = room.get_role(request.user)
if self.can_bypass_lobby(room=room, user=request.user, role=user_role):
self._update_participant_status(
room_id,
participant_id,
LobbyParticipantStatus.ACCEPTED,
settings.LOBBY_ACCEPTED_TIMEOUT
)
participant = self.handle_participant_entry(room_id, participant.id, True)
livekit_config = utils.generate_livekit_config(
room_id=room_id,
@@ -280,7 +275,7 @@ class LobbyService:
room_id: UUID,
participant_id: str,
allow_entry: bool,
) -> None:
) -> LobbyParticipant:
"""Handle decision on participant entry.
Updates participant status based on allow_entry:
@@ -298,7 +293,7 @@ class LobbyService:
"timeout": settings.LOBBY_DENIED_TIMEOUT,
}
self._update_participant_status(room_id, participant_id, **decision)
return self._update_participant_status(room_id, participant_id, **decision)
def _update_participant_status(
self,
@@ -306,7 +301,7 @@ class LobbyService:
participant_id: str,
status: LobbyParticipantStatus,
timeout: int,
) -> None:
) -> LobbyParticipant:
"""Update participant status with appropriate timeout."""
cache_key = self._get_cache_key(room_id, participant_id)
@@ -328,6 +323,8 @@ class LobbyService:
participant.status = status
cache.set(cache_key, participant.to_dict(), timeout=timeout)
return participant
def clear_room_cache(self, room_id: UUID) -> None:
"""Clear all participant entries from the cache for a specific room."""
@@ -221,6 +221,10 @@ def test_request_entry_public_room(settings):
# The accepted participant is persisted, out of the waiting list
lobby_keys = cache.keys(f"mocked-cache-prefix_{room.id}_*")
assert len(lobby_keys) == 1
ttl = cache.ttl(lobby_keys[0])
assert ttl is not None
assert ttl == pytest.approx(settings.LOBBY_ACCEPTED_TIMEOUT, abs=2000)
assert cache.get(lobby_keys[0])["status"] == "accepted"
@@ -268,6 +272,9 @@ def test_request_entry_authenticated_user_public_room(settings):
lobby_keys = cache.keys(f"mocked-cache-prefix_{room.id}_*")
assert len(lobby_keys) == 1
assert cache.get(lobby_keys[0])["status"] == "accepted"
ttl = cache.ttl(lobby_keys[0])
assert ttl is not None
assert ttl == pytest.approx(settings.LOBBY_ACCEPTED_TIMEOUT, abs=2000)
def test_request_entry_waiting_participant_public_room(settings):
@@ -318,6 +325,11 @@ def test_request_entry_waiting_participant_public_room(settings):
lobby_keys = cache.keys(f"mocked-cache-prefix_{room.id}_*")
assert len(lobby_keys) == 1
ttl = cache.ttl(lobby_keys[0])
assert ttl is not None
assert ttl == pytest.approx(settings.LOBBY_ACCEPTED_TIMEOUT, abs=2000)
assert cache.get(lobby_keys[0])["status"] == "accepted"
def test_request_entry_invalid_data():
"""Should return 400 for invalid request data."""
+68 -58
View File
@@ -7,7 +7,7 @@ Test lobby service.
import uuid
from unittest import mock
from django.conf import settings
from django.conf import settings as django_settings
from django.contrib.auth.models import AnonymousUser
from django.core.cache import cache
@@ -129,7 +129,7 @@ def test_get_cache_key(lobby_service, participant_id):
room = RoomFactory(access_level=RoomAccessLevel.RESTRICTED)
cache_key = lobby_service._get_cache_key(room.id, participant_id)
expected_key = f"{settings.LOBBY_KEY_PREFIX}_{room.id!s}_{participant_id}"
expected_key = f"{django_settings.LOBBY_KEY_PREFIX}_{room.id!s}_{participant_id}"
assert cache_key == expected_key
@@ -196,22 +196,26 @@ def test_can_bypass_lobby_private_room_with_any_role(role, lobby_service):
@mock.patch("core.utils.generate_livekit_config")
def test_request_entry_public_room(
mock_generate_config, lobby_service, participant_id, username
mock_generate_config, lobby_service, participant_id, username, settings
):
"""Test requesting entry to a public room."""
settings.LOBBY_KEY_PREFIX = "mocked-cache-prefix"
request = mock.Mock()
request.user = AnonymousUser()
room = RoomFactory(access_level=RoomAccessLevel.PUBLIC)
mocked_participant = LobbyParticipant(
status=LobbyParticipantStatus.UNKNOWN,
username=username,
id=participant_id,
color="#123456",
cache.set(
f"mocked-cache-prefix_{room.id}_{participant_id}",
{
"id": participant_id,
"username": username,
"status": "waiting",
"color": "#123456",
},
)
lobby_service._get_participant = mock.Mock(return_value=mocked_participant)
mock_generate_config.return_value = {"token": "test-token"}
participant, livekit_config = lobby_service.request_entry(
@@ -226,31 +230,33 @@ def test_request_entry_public_room(
username=username,
color=participant.color,
configuration=room.configuration,
participant_id="test-participant-id",
participant_id=participant_id,
role=None,
)
lobby_service._get_participant.assert_called_once_with(room.id, participant_id)
@mock.patch("core.utils.generate_livekit_config")
def test_request_entry_trusted_room(
mock_generate_config, lobby_service, participant_id, username
mock_generate_config, lobby_service, participant_id, username, settings
):
"""Test requesting entry to a trusted room when the user is authenticated."""
settings.LOBBY_KEY_PREFIX = "mocked-cache-prefix"
request = mock.Mock()
request.user = UserFactory()
room = RoomFactory(access_level=RoomAccessLevel.TRUSTED)
mocked_participant = LobbyParticipant(
status=LobbyParticipantStatus.UNKNOWN,
username=username,
id=participant_id,
color="#123456",
cache.set(
f"mocked-cache-prefix_{room.id}_{participant_id}",
{
"id": participant_id,
"username": username,
"status": "waiting",
"color": "#123456",
},
)
lobby_service._get_participant = mock.Mock(return_value=mocked_participant)
mock_generate_config.return_value = {"token": "test-token"}
participant, livekit_config = lobby_service.request_entry(
@@ -265,12 +271,10 @@ def test_request_entry_trusted_room(
username=username,
color=participant.color,
configuration=room.configuration,
participant_id="test-participant-id",
participant_id=participant_id,
role=None,
)
lobby_service._get_participant.assert_called_once_with(room.id, participant_id)
@mock.patch("core.services.lobby.LobbyService._notify_entry_request")
@mock.patch("core.services.lobby.LobbyService._create_participant")
@@ -339,21 +343,24 @@ def test_request_entry_waiting_participant(
@mock.patch("core.utils.generate_livekit_config")
def test_request_entry_accepted_participant(
mock_generate_config, lobby_service, participant_id, username
mock_generate_config, lobby_service, participant_id, username, settings
):
"""Test requesting entry for an accepted participant."""
settings.LOBBY_KEY_PREFIX = "mocked-cache-prefix"
request = mock.Mock()
request.user = AnonymousUser()
room = RoomFactory(access_level=RoomAccessLevel.RESTRICTED)
mocked_participant = LobbyParticipant(
status=LobbyParticipantStatus.ACCEPTED,
username=username,
id=participant_id,
color="#123456",
cache.set(
f"mocked-cache-prefix_{room.id}_{participant_id}",
{
"id": participant_id,
"username": username,
"status": "accepted",
"color": "#123456",
},
)
lobby_service._get_participant = mock.Mock(return_value=mocked_participant)
mock_generate_config.return_value = {"token": "test-token"}
@@ -372,14 +379,15 @@ def test_request_entry_accepted_participant(
participant_id="test-participant-id",
role=None,
)
lobby_service._get_participant.assert_called_once_with(room.id, participant_id)
@mock.patch("core.utils.generate_livekit_config")
def test_request_entry_participant_with_role(
mock_generate_config, lobby_service, participant_id, username
mock_generate_config, lobby_service, participant_id, username, settings
):
"""Test requesting entry for a participant with a role on the room."""
settings.LOBBY_KEY_PREFIX = "mocked-cache-prefix"
request = mock.Mock()
request.user = UserFactory()
@@ -387,13 +395,15 @@ def test_request_entry_participant_with_role(
UserResourceAccessFactory(resource=room, user=request.user, role="administrator")
mocked_participant = LobbyParticipant(
status=LobbyParticipantStatus.ACCEPTED,
username=username,
id=participant_id,
color="#123456",
cache.set(
f"mocked-cache-prefix_{room.id}_{participant_id}",
{
"id": participant_id,
"username": username,
"status": "accepted",
"color": "#123456",
},
)
lobby_service._get_participant = mock.Mock(return_value=mocked_participant)
mock_generate_config.return_value = {"token": "test-token"}
@@ -412,7 +422,6 @@ def test_request_entry_participant_with_role(
participant_id="test-participant-id",
role="administrator",
)
lobby_service._get_participant.assert_called_once_with(room.id, participant_id)
@mock.patch("core.services.lobby.cache")
@@ -422,7 +431,7 @@ def test_refresh_waiting_status(mock_cache, lobby_service, participant_id):
room = RoomFactory(access_level=RoomAccessLevel.RESTRICTED)
lobby_service.refresh_waiting_status(room.id, participant_id)
mock_cache.touch.assert_called_once_with(
"mocked_cache_key", settings.LOBBY_WAITING_TIMEOUT
"mocked_cache_key", django_settings.LOBBY_WAITING_TIMEOUT
)
@@ -433,7 +442,6 @@ def test_create_participant(
mock_cache,
lobby_service,
username,
settings,
):
"""A created participant is waiting, colored, and persisted."""
mock_generate_color.return_value = "#123456"
@@ -454,7 +462,7 @@ def test_create_participant(
mock_cache.set.assert_called_once_with(
"mocked_cache_key",
participant.to_dict(),
timeout=settings.LOBBY_WAITING_TIMEOUT,
timeout=django_settings.LOBBY_WAITING_TIMEOUT,
)
@@ -512,7 +520,7 @@ def test_list_waiting_participants_empty(mock_cache, lobby_service):
result = lobby_service.list_waiting_participants(room.id)
assert result == []
pattern = f"{settings.LOBBY_KEY_PREFIX}_{room.id!s}_*"
pattern = f"{django_settings.LOBBY_KEY_PREFIX}_{room.id!s}_*"
mock_cache.keys.assert_called_once_with(pattern)
mock_cache.get_many.assert_not_called()
@@ -521,7 +529,7 @@ def test_list_waiting_participants_empty(mock_cache, lobby_service):
def test_list_waiting_participants(mock_cache, lobby_service, participant_dict):
"""Test listing waiting participants with valid data."""
room = RoomFactory(access_level=RoomAccessLevel.RESTRICTED)
cache_key = f"{settings.LOBBY_KEY_PREFIX}_{room.id!s}_participant1"
cache_key = f"{django_settings.LOBBY_KEY_PREFIX}_{room.id!s}_participant1"
mock_cache.keys.return_value = [cache_key]
mock_cache.get_many.return_value = {cache_key: participant_dict}
@@ -530,7 +538,7 @@ def test_list_waiting_participants(mock_cache, lobby_service, participant_dict):
assert len(result) == 1
assert result[0]["status"] == "waiting"
assert result[0]["username"] == "test-username"
pattern = f"{settings.LOBBY_KEY_PREFIX}_{room.id!s}_*"
pattern = f"{django_settings.LOBBY_KEY_PREFIX}_{room.id!s}_*"
mock_cache.keys.assert_called_once_with(pattern)
mock_cache.get_many.assert_called_once_with([cache_key])
@@ -539,8 +547,8 @@ def test_list_waiting_participants(mock_cache, lobby_service, participant_dict):
def test_list_waiting_participants_multiple(mock_cache, lobby_service):
"""Test listing multiple waiting participants with valid data."""
room = RoomFactory(access_level=RoomAccessLevel.RESTRICTED)
cache_key1 = f"{settings.LOBBY_KEY_PREFIX}_{room.id!s}_participant1"
cache_key2 = f"{settings.LOBBY_KEY_PREFIX}_{room.id!s}_participant2"
cache_key1 = f"{django_settings.LOBBY_KEY_PREFIX}_{room.id!s}_participant1"
cache_key2 = f"{django_settings.LOBBY_KEY_PREFIX}_{room.id!s}_participant2"
participant1 = {
"status": "waiting",
@@ -573,7 +581,7 @@ def test_list_waiting_participants_multiple(mock_cache, lobby_service):
# Verify all participants have waiting status
assert all(p["status"] == "waiting" for p in result)
pattern = f"{settings.LOBBY_KEY_PREFIX}_{room.id!s}_*"
pattern = f"{django_settings.LOBBY_KEY_PREFIX}_{room.id!s}_*"
mock_cache.keys.assert_called_once_with(pattern)
mock_cache.get_many.assert_called_once_with([cache_key1, cache_key2])
@@ -582,7 +590,7 @@ def test_list_waiting_participants_multiple(mock_cache, lobby_service):
def test_list_waiting_participants_corrupted_data(mock_cache, lobby_service):
"""Test listing waiting participants with corrupted data."""
room = RoomFactory(access_level=RoomAccessLevel.RESTRICTED)
cache_key = f"{settings.LOBBY_KEY_PREFIX}_{room.id!s}_participant1"
cache_key = f"{django_settings.LOBBY_KEY_PREFIX}_{room.id!s}_participant1"
mock_cache.keys.return_value = [cache_key]
mock_cache.get_many.return_value = {cache_key: {"invalid": "data"}}
@@ -596,8 +604,8 @@ def test_list_waiting_participants_corrupted_data(mock_cache, lobby_service):
def test_list_waiting_participants_partially_corrupted(mock_cache, lobby_service):
"""Test listing waiting participants with one valid and one corrupted entry."""
room = RoomFactory(access_level=RoomAccessLevel.RESTRICTED)
cache_key1 = f"{settings.LOBBY_KEY_PREFIX}_{room.id!s}_participant1"
cache_key2 = f"{settings.LOBBY_KEY_PREFIX}_{room.id!s}_participant2"
cache_key1 = f"{django_settings.LOBBY_KEY_PREFIX}_{room.id!s}_participant1"
cache_key2 = f"{django_settings.LOBBY_KEY_PREFIX}_{room.id!s}_participant2"
valid_participant = {
"status": "waiting",
@@ -626,7 +634,7 @@ def test_list_waiting_participants_partially_corrupted(mock_cache, lobby_service
mock_cache.delete.assert_called_once_with(cache_key1)
# Verify both cache keys were queried
pattern = f"{settings.LOBBY_KEY_PREFIX}_{room.id!s}_*"
pattern = f"{django_settings.LOBBY_KEY_PREFIX}_{room.id!s}_*"
mock_cache.keys.assert_called_once_with(pattern)
mock_cache.get_many.assert_called_once_with([cache_key1, cache_key2])
@@ -635,8 +643,8 @@ def test_list_waiting_participants_partially_corrupted(mock_cache, lobby_service
def test_list_waiting_participants_non_waiting(mock_cache, lobby_service):
"""Test listing only waiting participants (not accepted/denied)."""
room = RoomFactory(access_level=RoomAccessLevel.RESTRICTED)
cache_key1 = f"{settings.LOBBY_KEY_PREFIX}_{room.id!s}_participant1"
cache_key2 = f"{settings.LOBBY_KEY_PREFIX}_{room.id!s}_participant2"
cache_key1 = f"{django_settings.LOBBY_KEY_PREFIX}_{room.id!s}_participant1"
cache_key2 = f"{django_settings.LOBBY_KEY_PREFIX}_{room.id!s}_participant2"
participant1 = {
"status": "waiting",
@@ -674,7 +682,7 @@ def test_handle_participant_entry_allow(mock_update, lobby_service, participant_
room.id,
participant_id,
status=LobbyParticipantStatus.ACCEPTED,
timeout=settings.LOBBY_ACCEPTED_TIMEOUT,
timeout=django_settings.LOBBY_ACCEPTED_TIMEOUT,
)
@@ -688,7 +696,7 @@ def test_handle_participant_entry_deny(mock_update, lobby_service, participant_i
room.id,
participant_id,
status=LobbyParticipantStatus.DENIED,
timeout=settings.LOBBY_DENIED_TIMEOUT,
timeout=django_settings.LOBBY_DENIED_TIMEOUT,
)
@@ -829,14 +837,16 @@ def test_clear_participant_cache(lobby_service):
room_id = uuid.uuid4()
participant_id = "test-participant-id"
cache_key = f"{settings.LOBBY_KEY_PREFIX}_{room_id!s}_{participant_id}"
cache_key = f"{django_settings.LOBBY_KEY_PREFIX}_{room_id!s}_{participant_id}"
participant_data = {
"status": "waiting",
"username": "test-username",
"id": participant_id,
"color": "#123456",
}
cache.set(cache_key, participant_data, timeout=settings.LOBBY_WAITING_TIMEOUT)
cache.set(
cache_key, participant_data, timeout=django_settings.LOBBY_WAITING_TIMEOUT
)
assert cache.get(cache_key) is not None
lobby_service.clear_participant_cache(room_id, participant_id)
@@ -848,7 +858,7 @@ def test_clear_participant_cache_nonexistent(lobby_service):
room_id = uuid.uuid4()
participant_id = "nonexistent-participant"
cache_key = f"{settings.LOBBY_KEY_PREFIX}_{room_id!s}_{participant_id}"
cache_key = f"{django_settings.LOBBY_KEY_PREFIX}_{room_id!s}_{participant_id}"
assert cache.get(cache_key) is None
lobby_service.clear_participant_cache(room_id, participant_id)