Files
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 13:30:13 +08:00

101 lines
3.3 KiB
Python

"""E2E for layer-3 headless re-auth (gated on a real persistent profile).
This test drives a REAL headless browser against the persistent login profile
and is excluded from CI by default (``-m e2e`` + a profile/opt-in gate). It
exists to exercise the one path the unit tests fake: the actual
launch -> navigate -> classify -> capture -> persist sequence against a live
Google session.
Run locally, after ``notebooklm login`` has populated the profile, with::
NOTEBOOKLM_HEADLESS_REAUTH=1 pytest tests/e2e/test_headless_reauth.py -m e2e
It is SKIPPED unless both:
* the persistent browser profile exists and is non-empty (a real Google
session to harvest), and
* the operator opted in via ``NOTEBOOKLM_HEADLESS_REAUTH=1`` (the same opt-in
the production mid-RPC path requires) — so the test never silently drives a
browser in an environment that did not ask for it.
"""
from __future__ import annotations
import os
import pytest
from notebooklm._auth.headless_reauth import (
HeadlessReauthStatus,
attempt_headless_reauth,
)
from notebooklm.paths import get_browser_profile_dir, get_storage_path
def _profile_is_reusable() -> bool:
profile = get_browser_profile_dir()
if not profile.is_dir():
return False
try:
next(profile.iterdir())
except (StopIteration, OSError):
return False
return True
def _playwright_available() -> bool:
"""True when the ``browser`` extra is importable.
Without it ``attempt_headless_reauth`` returns ``UNAVAILABLE`` (nothing to
drive), which is NOT one of the SUCCESS/FAILED outcomes this test asserts —
so the gate must skip rather than let the test fail on a missing optional
dependency.
"""
try:
import playwright.sync_api # noqa: F401
except ImportError:
return False
return True
_GATE = pytest.mark.skipif(
os.environ.get("NOTEBOOKLM_HEADLESS_REAUTH") != "1"
or not _profile_is_reusable()
or not _playwright_available(),
reason=(
"headless re-auth e2e requires NOTEBOOKLM_HEADLESS_REAUTH=1, a non-empty "
"persistent browser profile (run 'notebooklm login' first), and the "
"'browser' extra installed"
),
)
@pytest.mark.e2e
@_GATE
def test_headless_reauth_against_live_profile() -> None:
"""Drive a real headless re-auth and assert an honest, typed outcome.
A live profile session yields SUCCESS (cookies re-minted + persisted); an
expired profile session yields FAILED. UNAVAILABLE should not occur here
because the gate already proved opt-in + a reusable profile. Either way the
result is one of the three honest, typed outcomes — never a silent ``None``.
"""
result = attempt_headless_reauth(
storage_path=get_storage_path(),
allow_headless=True,
)
assert result.status in {
HeadlessReauthStatus.SUCCESS,
HeadlessReauthStatus.FAILED,
}, f"unexpected status {result.status} (reason: {result.reason})"
if result.status is HeadlessReauthStatus.SUCCESS:
assert result.succeeded is True
assert result.storage_path == get_storage_path()
assert get_storage_path().exists()
else:
# Honest failure — the profile's Google session is also expired.
assert result.succeeded is False
assert result.storage_path is None