Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,11 @@ async def list_sessions(
self, *, app_name: str, user_id: Optional[str] = None
) -> ListSessionsResponse:
"""Lists sessions from Firestore."""
if user_id:
if user_id == "":
# Firestore rejects a document path with an empty segment, so no session
# can be stored for this user, and querying for one would fail.
return ListSessionsResponse()
if user_id is not None:
query = self._get_sessions_ref(app_name, user_id).where(
filter=FieldFilter("appName", "==", app_name)
)
Expand All @@ -392,7 +396,7 @@ def _iter_sessions_data() -> Iterator[dict[str, Any]]:
app_state = app_doc.to_dict() if app_doc.exists else {}

user_states_map = {}
if user_id:
if user_id is not None:
user_ref = (
self.client.collection(self.user_state_collection)
.document(app_name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,22 @@ async def mock_get_all(refs):
assert _where_filter(where) == ("appName", "==", app_name)


@pytest.mark.asyncio
async def test_list_sessions_with_empty_user_id_returns_no_sessions(
mock_firestore_client,
):
"""user_id="" must not fall through to the all-users query."""
service = FirestoreSessionService(client=mock_firestore_client)
mock_firestore_client.collection_group.return_value.where.return_value.get = (
mock.AsyncMock(return_value=[])
)

response = await service.list_sessions(app_name="test_app", user_id="")

assert response.sessions == []
mock_firestore_client.collection_group.assert_not_called()


@pytest.mark.asyncio
async def test_get_user_state_returns_stored_user_state(mock_firestore_client):
"""get_user_state returns the user_states document for the app and user."""
Expand Down
Loading