""" Tests for web/auth/session_cleanup.py Tests cover: - cleanup_stale_sessions() function - Skip conditions (should_skip, no username, user connected, temp_auth_token, no encryption) - Session clearing behavior (no session_id, session_id with no password, session_id with password) """ from unittest.mock import MagicMock, patch from flask import Flask, session def _make_app(): """Create a minimal Flask test app with a secret key.""" app = Flask(__name__) app.secret_key = "test-secret-key" return app class TestCleanupStaleSessions: """Tests for cleanup_stale_sessions function.""" def test_skips_when_should_skip_returns_true(self): """Should return immediately when should_skip_session_cleanup() is True.""" app = _make_app() with ( patch( "local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup", return_value=True, ), patch( "local_deep_research.web.auth.session_cleanup.db_manager" ) as mock_db, ): from local_deep_research.web.auth.session_cleanup import ( cleanup_stale_sessions, ) with app.test_request_context("/"): session["username"] = "testuser" cleanup_stale_sessions() # db_manager should never be consulted mock_db.is_user_connected.assert_not_called() # Session should remain intact assert session.get("username") == "testuser" def test_does_nothing_when_no_username_in_session(self): """Should do nothing when session has no username.""" app = _make_app() with ( patch( "local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup", return_value=False, ), patch( "local_deep_research.web.auth.session_cleanup.db_manager" ) as mock_db, ): from local_deep_research.web.auth.session_cleanup import ( cleanup_stale_sessions, ) with app.test_request_context("/"): # No username set in session cleanup_stale_sessions() mock_db.is_user_connected.assert_not_called() def test_does_nothing_when_user_is_connected(self): """Should do nothing when db_manager.is_user_connected returns True.""" app = _make_app() with ( patch( "local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup", return_value=False, ), patch( "local_deep_research.web.auth.session_cleanup.db_manager" ) as mock_db, ): mock_db.is_user_connected.return_value = True from local_deep_research.web.auth.session_cleanup import ( cleanup_stale_sessions, ) with app.test_request_context("/"): session["username"] = "testuser" cleanup_stale_sessions() # Session should remain intact assert session.get("username") == "testuser" def test_does_nothing_when_temp_auth_token_exists(self): """Should not clear session when temp_auth_token is present (recovery possible).""" app = _make_app() with ( patch( "local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup", return_value=False, ), patch( "local_deep_research.web.auth.session_cleanup.db_manager" ) as mock_db, ): mock_db.is_user_connected.return_value = False mock_db.has_encryption = True from local_deep_research.web.auth.session_cleanup import ( cleanup_stale_sessions, ) with app.test_request_context("/"): session["username"] = "testuser" session["temp_auth_token"] = "some-recovery-token" cleanup_stale_sessions() # Session should remain intact assert session.get("username") == "testuser" def test_does_nothing_when_db_has_no_encryption(self): """Should not clear session when db_manager.has_encryption is False.""" app = _make_app() with ( patch( "local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup", return_value=False, ), patch( "local_deep_research.web.auth.session_cleanup.db_manager" ) as mock_db, ): mock_db.is_user_connected.return_value = False mock_db.has_encryption = False from local_deep_research.web.auth.session_cleanup import ( cleanup_stale_sessions, ) with app.test_request_context("/"): session["username"] = "testuser" cleanup_stale_sessions() # Session should remain intact because encryption is off assert session.get("username") == "testuser" def test_clears_session_when_no_session_id_and_no_recovery(self): """Should clear session when there is no session_id (no way to recover).""" app = _make_app() with ( patch( "local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup", return_value=False, ), patch( "local_deep_research.web.auth.session_cleanup.db_manager" ) as mock_db, ): mock_db.is_user_connected.return_value = False mock_db.has_encryption = True from local_deep_research.web.auth.session_cleanup import ( cleanup_stale_sessions, ) with app.test_request_context("/"): session["username"] = "testuser" # No session_id, no temp_auth_token cleanup_stale_sessions() # Session should be cleared assert session.get("username") is None def test_clears_session_when_session_id_but_no_password_in_store(self): """Should clear session when session_id exists but password store has no password.""" app = _make_app() mock_password_store = MagicMock() mock_password_store.get_session_password.return_value = None with ( patch( "local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup", return_value=False, ), patch( "local_deep_research.web.auth.session_cleanup.db_manager" ) as mock_db, patch( "local_deep_research.database.session_passwords.session_password_store", mock_password_store, ), ): mock_db.is_user_connected.return_value = False mock_db.has_encryption = True from local_deep_research.web.auth.session_cleanup import ( cleanup_stale_sessions, ) with app.test_request_context("/"): session["username"] = "testuser" session["session_id"] = "sess-abc-123" cleanup_stale_sessions() # Session should be cleared assert session.get("username") is None mock_password_store.get_session_password.assert_called_once_with( "testuser", "sess-abc-123" ) def test_does_not_clear_session_when_password_found_in_store(self): """Should NOT clear session when password IS found in the session password store.""" app = _make_app() mock_password_store = MagicMock() mock_password_store.get_session_password.return_value = ( "stored-password" ) with ( patch( "local_deep_research.web.auth.session_cleanup.should_skip_session_cleanup", return_value=False, ), patch( "local_deep_research.web.auth.session_cleanup.db_manager" ) as mock_db, patch( "local_deep_research.database.session_passwords.session_password_store", mock_password_store, ), ): mock_db.is_user_connected.return_value = False mock_db.has_encryption = True from local_deep_research.web.auth.session_cleanup import ( cleanup_stale_sessions, ) with app.test_request_context("/"): session["username"] = "testuser" session["session_id"] = "sess-abc-123" cleanup_stale_sessions() # Session should remain intact assert session.get("username") == "testuser" assert session.get("session_id") == "sess-abc-123" mock_password_store.get_session_password.assert_called_once_with( "testuser", "sess-abc-123" )