09e9f3545f
Test / Code Quality (push) Has been cancelled
Test / Test (macos-latest, Python 3.10) (push) Has been cancelled
Test / Test (macos-latest, Python 3.11) (push) Has been cancelled
Test / Test (macos-latest, Python 3.12) (push) Has been cancelled
Test / Test (macos-latest, Python 3.13) (push) Has been cancelled
Test / Test (macos-latest, Python 3.14) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.10) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.11) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.12) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.13) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.14) (push) Has been cancelled
Test / Test (windows-latest, Python 3.10) (push) Has been cancelled
Test / Test (windows-latest, Python 3.11) (push) Has been cancelled
Test / Test (windows-latest, Python 3.12) (push) Has been cancelled
Test / Test (windows-latest, Python 3.13) (push) Has been cancelled
Test / Test (windows-latest, Python 3.14) (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
dependency-audit / pip-audit (push) Has been cancelled
101 lines
4.2 KiB
Python
101 lines
4.2 KiB
Python
"""Unit tests for the Firefox-family cookie helper error branches.
|
|
|
|
``_read_firefox_container_cookies`` maps every extractor failure to a typed
|
|
:class:`~notebooklm.cli.services.login.outcomes.BrowserCookieOutcome` carrying
|
|
the friendly message; the command layer (or ``refresh._exit_on_outcome``)
|
|
renders the message and exits. These tests pin the four terminal error
|
|
handlers (each returns an outcome whose ``message`` carries the original
|
|
text) and the early return in ``_maybe_warn_firefox_containers_in_use`` when
|
|
no profile is found.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sqlite3
|
|
from unittest.mock import MagicMock
|
|
|
|
from notebooklm.cli.services.login import firefox_accounts
|
|
from notebooklm.cli.services.login.outcomes import BrowserCookieOutcome
|
|
from tests._fixtures.login_io import make_recording_io
|
|
|
|
|
|
def _fake_containers_module(profile_path, *, extract_side_effect=None):
|
|
"""Build a stand-in for the ``_firefox_containers`` module."""
|
|
mod = MagicMock()
|
|
mod.find_firefox_profile_path.return_value = profile_path
|
|
mod.resolve_container_id.return_value = "none"
|
|
if extract_side_effect is not None:
|
|
mod.extract_firefox_container_cookies.side_effect = extract_side_effect
|
|
return mod
|
|
|
|
|
|
class TestReadFirefoxContainerCookiesErrors:
|
|
def test_file_not_found_returns_outcome(self, tmp_path):
|
|
mod = _fake_containers_module(
|
|
tmp_path, extract_side_effect=FileNotFoundError("no cookies.sqlite")
|
|
)
|
|
result = firefox_accounts._read_firefox_container_cookies(
|
|
make_recording_io(), "none", verbose=False, firefox_containers=mod
|
|
)
|
|
assert isinstance(result, BrowserCookieOutcome)
|
|
assert "no cookies.sqlite" in result.message
|
|
|
|
def test_oserror_routes_through_rookiepy_handler(self, tmp_path):
|
|
mod = _fake_containers_module(tmp_path, extract_side_effect=OSError("database is locked"))
|
|
result = firefox_accounts._read_firefox_container_cookies(
|
|
make_recording_io(), "none", verbose=False, firefox_containers=mod
|
|
)
|
|
assert isinstance(result, BrowserCookieOutcome)
|
|
# The locked-DB message from _handle_rookiepy_error is surfaced.
|
|
assert "database is locked" in result.message
|
|
|
|
def test_runtime_error_routes_through_rookiepy_handler(self, tmp_path):
|
|
mod = _fake_containers_module(
|
|
tmp_path, extract_side_effect=RuntimeError("totally unexpected")
|
|
)
|
|
result = firefox_accounts._read_firefox_container_cookies(
|
|
make_recording_io(), "none", verbose=False, firefox_containers=mod
|
|
)
|
|
assert isinstance(result, BrowserCookieOutcome)
|
|
|
|
def test_sqlite_database_error_returns_outcome(self, tmp_path):
|
|
mod = _fake_containers_module(
|
|
tmp_path, extract_side_effect=sqlite3.DatabaseError("malformed db")
|
|
)
|
|
result = firefox_accounts._read_firefox_container_cookies(
|
|
make_recording_io(), "none", verbose=False, firefox_containers=mod
|
|
)
|
|
assert isinstance(result, BrowserCookieOutcome)
|
|
assert "malformed db" in result.message
|
|
|
|
def test_success_returns_cookies(self, tmp_path):
|
|
mod = _fake_containers_module(tmp_path)
|
|
mod.extract_firefox_container_cookies.return_value = [{"name": "SID"}]
|
|
cookies = firefox_accounts._read_firefox_container_cookies(
|
|
make_recording_io(), "none", verbose=False, firefox_containers=mod
|
|
)
|
|
assert cookies == [{"name": "SID"}]
|
|
|
|
|
|
class TestMaybeWarnFirefoxContainersInUse:
|
|
def test_no_profile_returns_silently(self):
|
|
mod = MagicMock()
|
|
mod.find_firefox_profile_path.return_value = None
|
|
io = make_recording_io()
|
|
|
|
firefox_accounts._maybe_warn_firefox_containers_in_use(io, firefox_containers=mod)
|
|
|
|
mod.has_container_cookies_in_use.assert_not_called()
|
|
assert io.emitted == []
|
|
|
|
def test_warns_when_container_cookies_in_use(self, tmp_path):
|
|
mod = MagicMock()
|
|
mod.find_firefox_profile_path.return_value = tmp_path
|
|
mod.has_container_cookies_in_use.return_value = True
|
|
io = make_recording_io()
|
|
|
|
firefox_accounts._maybe_warn_firefox_containers_in_use(io, firefox_containers=mod)
|
|
|
|
assert len(io.emitted) == 1
|
|
assert "Multi-Account Container" in io.emitted[0]
|