Skip to content

fix(sessions): list only the empty user's sessions in SqliteSessionService - #7171

Open
yupengtang wants to merge 1 commit into
google:mainfrom
yupengtang:fix-sqlite-list-sessions-empty-user-id
Open

yupengtang wants to merge 1 commit into
google:mainfrom
yupengtang:fix-sqlite-list-sessions-empty-user-id

Conversation

@yupengtang

Copy link
Copy Markdown

Link to Issue or Description of Change

2. Or, if no issue exists, describe the change:

Problem:

SqliteSessionService.list_sessions picks between the per-user query and the all-users query with if user_id:. An empty string is falsy, so list_sessions(app_name=..., user_id='') returns every user's sessions, each merged with that user's user: state. create_session accepts user_id='', and the in-memory, database and Redis services all return only that user's sessions.

This is the same bug 4b26bba fixed in RedisSessionService. The note about it in tests/unittests/sessions/_conformance.py is still there, although Redis now passes.

Solution:

Check user_id is not None in both places in list_sessions, matching the Redis fix. Add a contract test that runs on every registered backend, and remove the stale Redis note since there is now a test for it. PerAgentDatabaseSessionService wraps the SQLite service, so it is fixed too.

FirestoreSessionService.list_sessions has the same check, but Firestore rejects empty document ids, so a session with user_id='' can't exist there. I left it alone.

Testing Plan

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

test_list_sessions_with_empty_user_id_lists_only_that_user passes on all six backends in _conformance.BACKENDS. With the sqlite_session_service.py change reverted, it fails for sqlite and per_agent_database only.

$ pytest tests/unittests/sessions tests/unittests/integrations/redis tests/unittests/cli/utils
1021 passed, 5 xfailed, 142 warnings in 41.44s

Manual End-to-End (E2E) Tests:

import asyncio
import tempfile

from google.adk.sessions.sqlite_session_service import SqliteSessionService


async def main():
  with tempfile.TemporaryDirectory() as tmp:
    service = SqliteSessionService(f"{tmp}/sessions.db")
    await service.create_session(app_name="app", user_id="", session_id="s1")
    await service.create_session(
        app_name="app",
        user_id="alice",
        session_id="s2",
        state={"user:email": "alice@example.com"},
    )
    response = await service.list_sessions(app_name="app", user_id="")
    for session in response.sessions:
      print(session.user_id or "''", session.id, session.state)


asyncio.run(main())

Before:

'' s1 {}
alice s2 {'user:email': 'alice@example.com'}

After:

'' s1 {}

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

…rvice

list_sessions chose between the per-user and all-users queries with a
truthiness check, so user_id='' listed every user's sessions, merged with
their user-scoped state. Check for None instead, as RedisSessionService
does since 4b26bba, and add a contract test for the empty user id. The
Redis note about the same divergence is removed since that backend
already passes it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants