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
201 lines
8.1 KiB
Python
201 lines
8.1 KiB
Python
"""Tests for ``notebooklm status`` and ``notebooklm clear``.
|
|
|
|
This file was extracted from the legacy ``test_session.py`` as part of
|
|
D1 PR-3 (test-monkeypatch-policy migration). The shared fixtures and
|
|
helpers live in ``_session_helpers.py``; the proxy-block-aware
|
|
``patch_session_login_dual`` lives in ``tests/_fixtures``.
|
|
"""
|
|
|
|
import json
|
|
from unittest.mock import patch
|
|
|
|
import notebooklm.cli.services.session_context as session_context_module
|
|
from notebooklm.notebooklm_cli import cli
|
|
|
|
|
|
class TestStatusCommand:
|
|
def test_status_no_context(self, runner, mock_context_file):
|
|
"""Test status command when no notebook is selected."""
|
|
# Ensure context file doesn't exist
|
|
if mock_context_file.exists():
|
|
mock_context_file.unlink()
|
|
|
|
result = runner.invoke(cli, ["status"])
|
|
|
|
assert result.exit_code == 0
|
|
assert "No notebook selected" in result.output or "use" in result.output.lower()
|
|
|
|
def test_status_with_context(self, runner, mock_context_file):
|
|
"""Test status command shows current notebook context."""
|
|
# Create context file with notebook info
|
|
context_data = {
|
|
"notebook_id": "nb_test_123",
|
|
"title": "My Test Notebook",
|
|
"is_owner": True,
|
|
"created_at": "2024-01-15",
|
|
}
|
|
mock_context_file.write_text(json.dumps(context_data))
|
|
|
|
result = runner.invoke(cli, ["status"])
|
|
|
|
assert result.exit_code == 0
|
|
assert "nb_test_123" in result.output or "My Test Notebook" in result.output
|
|
|
|
def test_status_with_conversation(self, runner, mock_context_file):
|
|
"""Test status command shows conversation ID when set."""
|
|
context_data = {
|
|
"notebook_id": "nb_conv_test",
|
|
"title": "Notebook with Conversation",
|
|
"is_owner": True,
|
|
"created_at": "2024-01-15",
|
|
"conversation_id": "conv_abc123",
|
|
}
|
|
mock_context_file.write_text(json.dumps(context_data))
|
|
|
|
result = runner.invoke(cli, ["status"])
|
|
|
|
assert result.exit_code == 0
|
|
assert "conv_abc123" in result.output or "Conversation" in result.output
|
|
|
|
def test_status_json_output_with_context(self, runner, mock_context_file):
|
|
"""Test status --json outputs valid JSON."""
|
|
context_data = {
|
|
"notebook_id": "nb_json_test",
|
|
"title": "JSON Test Notebook",
|
|
"is_owner": True,
|
|
"created_at": "2024-01-15",
|
|
}
|
|
mock_context_file.write_text(json.dumps(context_data))
|
|
|
|
result = runner.invoke(cli, ["status", "--json"])
|
|
|
|
assert result.exit_code == 0
|
|
# Should be valid JSON
|
|
output_data = json.loads(result.output)
|
|
assert output_data["has_context"] is True
|
|
assert output_data["notebook"]["id"] == "nb_json_test"
|
|
|
|
def test_status_json_output_no_context(self, runner, mock_context_file):
|
|
"""Test status --json outputs valid JSON when no context."""
|
|
if mock_context_file.exists():
|
|
mock_context_file.unlink()
|
|
|
|
result = runner.invoke(cli, ["status", "--json"])
|
|
|
|
assert result.exit_code == 0
|
|
output_data = json.loads(result.output)
|
|
assert output_data["has_context"] is False
|
|
assert output_data["notebook"] is None
|
|
|
|
def test_status_handles_corrupted_context_file(self, runner, mock_context_file):
|
|
"""Test status handles corrupted context file gracefully."""
|
|
# Write invalid JSON
|
|
mock_context_file.write_text("{ invalid json }")
|
|
|
|
result = runner.invoke(cli, ["status"])
|
|
|
|
# Should not crash, should show minimal info or no context
|
|
assert result.exit_code == 0
|
|
|
|
|
|
# =============================================================================
|
|
# CLEAR COMMAND TESTS
|
|
# =============================================================================
|
|
|
|
|
|
class TestClearCommand:
|
|
def test_clear_removes_context(self, runner, mock_context_file):
|
|
"""Test clear command removes context file."""
|
|
# Create context file
|
|
context_data = {"notebook_id": "nb_to_clear", "title": "Clear Me"}
|
|
mock_context_file.write_text(json.dumps(context_data))
|
|
assert mock_context_file.exists(), "Precondition: context file should exist"
|
|
|
|
result = runner.invoke(cli, ["clear"])
|
|
|
|
assert result.exit_code == 0
|
|
assert "cleared" in result.output.lower() or "Context" in result.output
|
|
# Validate behaviour, not just exit/output: the context file must be
|
|
# gone (or empty) after the command runs. Without this, a regression
|
|
# that printed "cleared" but left the file in place would slip past.
|
|
assert not mock_context_file.exists() or not mock_context_file.read_text().strip()
|
|
|
|
def test_clear_when_no_context(self, runner, mock_context_file):
|
|
"""Test clear command when no context exists."""
|
|
if mock_context_file.exists():
|
|
mock_context_file.unlink()
|
|
|
|
result = runner.invoke(cli, ["clear"])
|
|
|
|
# Should succeed even if no context exists
|
|
assert result.exit_code == 0
|
|
|
|
|
|
# =============================================================================
|
|
# EDGE CASES
|
|
# =============================================================================
|
|
|
|
|
|
class TestStatusPaths:
|
|
"""Tests for status --paths flag."""
|
|
|
|
def test_status_paths_flag_shows_table(self, runner, mock_context_file):
|
|
"""Test status --paths shows configuration paths table."""
|
|
with patch.object(session_context_module, "get_path_info") as mock_path_info:
|
|
mock_path_info.return_value = {
|
|
"home_dir": "/home/test/.notebooklm",
|
|
"home_source": "default",
|
|
"storage_path": "/home/test/.notebooklm/storage_state.json",
|
|
"context_path": "/home/test/.notebooklm/context.json",
|
|
"browser_profile_dir": "/home/test/.notebooklm/browser_profile",
|
|
}
|
|
|
|
result = runner.invoke(cli, ["status", "--paths"])
|
|
|
|
assert result.exit_code == 0
|
|
assert "Configuration Paths" in result.output
|
|
assert "/home/test/.notebooklm" in result.output
|
|
assert "storage_state.json" in result.output
|
|
|
|
def test_status_paths_json_output(self, runner, mock_context_file):
|
|
"""Test status --paths --json outputs path info as JSON."""
|
|
with patch.object(session_context_module, "get_path_info") as mock_path_info:
|
|
mock_path_info.return_value = {
|
|
"home_dir": "/custom/path/.notebooklm",
|
|
"home_source": "NOTEBOOKLM_HOME",
|
|
"storage_path": "/custom/path/.notebooklm/storage_state.json",
|
|
"context_path": "/custom/path/.notebooklm/context.json",
|
|
"browser_profile_dir": "/custom/path/.notebooklm/browser_profile",
|
|
}
|
|
|
|
result = runner.invoke(cli, ["status", "--paths", "--json"])
|
|
|
|
assert result.exit_code == 0
|
|
output_data = json.loads(result.output)
|
|
assert "paths" in output_data
|
|
assert output_data["paths"]["home_dir"] == "/custom/path/.notebooklm"
|
|
assert output_data["paths"]["home_source"] == "NOTEBOOKLM_HOME"
|
|
|
|
def test_status_paths_shows_auth_json_note(self, runner, mock_context_file, monkeypatch):
|
|
"""Test status --paths shows note when NOTEBOOKLM_AUTH_JSON is set."""
|
|
monkeypatch.setenv("NOTEBOOKLM_AUTH_JSON", '{"cookies":[]}')
|
|
|
|
with patch.object(session_context_module, "get_path_info") as mock_path_info:
|
|
mock_path_info.return_value = {
|
|
"home_dir": "/home/test/.notebooklm",
|
|
"home_source": "default",
|
|
"storage_path": "/home/test/.notebooklm/storage_state.json",
|
|
"context_path": "/home/test/.notebooklm/context.json",
|
|
"browser_profile_dir": "/home/test/.notebooklm/browser_profile",
|
|
}
|
|
|
|
result = runner.invoke(cli, ["status", "--paths"])
|
|
|
|
assert result.exit_code == 0
|
|
assert "NOTEBOOKLM_AUTH_JSON is set" in result.output
|
|
|
|
|
|
# =============================================================================
|
|
# AUTH CHECK COMMAND TESTS
|
|
# =============================================================================
|