d9861aa6c3
- Add login_command function with QR code login, cookie import, and status check - Add login subcommand with --import-cookie and --status options - Update CLI help text with login examples - Fix mock paths in tests to match actual import locations Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
169 lines
6.3 KiB
Python
169 lines
6.3 KiB
Python
"""Tests for login CLI subcommand.
|
|
|
|
Tests the login_command function and CLI integration.
|
|
"""
|
|
|
|
import json
|
|
from unittest.mock import MagicMock, patch, AsyncMock
|
|
import pytest
|
|
|
|
from kb_workflow.kb_workflow import login_command
|
|
|
|
|
|
class TestLoginCommand:
|
|
"""Test suite for login CLI command."""
|
|
|
|
@pytest.fixture
|
|
def mock_settings(self):
|
|
"""Mock settings with empty cookie."""
|
|
settings = MagicMock()
|
|
settings.intermediate_path = "/tmp/intermediate"
|
|
settings.zhihu_cookie = MagicMock()
|
|
settings.zhihu_cookie.get_secret_value = MagicMock(return_value="")
|
|
return settings
|
|
|
|
@pytest.fixture
|
|
def mock_settings_with_cookie(self):
|
|
"""Mock settings with valid cookie."""
|
|
settings = MagicMock()
|
|
settings.intermediate_path = "/tmp/intermediate"
|
|
settings.zhihu_cookie = MagicMock()
|
|
settings.zhihu_cookie.get_secret_value = MagicMock(
|
|
return_value="z_c0=test_cookie_value"
|
|
)
|
|
return settings
|
|
|
|
@pytest.fixture
|
|
def mock_login_result_success(self):
|
|
"""Mock successful login result."""
|
|
from kb_workflow.auth.zhihu_login import ZhihuLoginResult
|
|
return ZhihuLoginResult(
|
|
success=True,
|
|
cookie_str="z_c0=valid_cookie; _xsrf=xsrf_value",
|
|
qrcode_path="/tmp/qrcode.png"
|
|
)
|
|
|
|
@pytest.fixture
|
|
def mock_validation_result_valid(self):
|
|
"""Mock valid cookie validation result."""
|
|
from kb_workflow.auth.zhihu_login import CookieValidationResult
|
|
return CookieValidationResult(
|
|
valid=True,
|
|
username="TestUser",
|
|
user_id="12345678"
|
|
)
|
|
|
|
def test_login_default_mode(
|
|
self, mock_settings, mock_login_result_success
|
|
):
|
|
"""Test 1: login_default_mode - Default starts QR code login."""
|
|
with patch('kb_workflow.pipeline.config.get_settings', return_value=mock_settings), \
|
|
patch('kb_workflow.auth.cookie_manager.CookieManager') as MockManager, \
|
|
patch('kb_workflow.auth.ZhihuLogin') as MockLogin:
|
|
|
|
# Setup mock
|
|
mock_login_instance = MagicMock()
|
|
mock_login_instance.login_by_qrcode.return_value = mock_login_result_success
|
|
MockLogin.return_value = mock_login_instance
|
|
mock_manager = MagicMock()
|
|
MockManager.return_value = mock_manager
|
|
|
|
# Act
|
|
result = login_command()
|
|
|
|
# Assert
|
|
assert result["success"] is True
|
|
assert "cookie_str" in result
|
|
mock_manager.save_cookie.assert_called_once()
|
|
|
|
def test_login_import_cookie(self, mock_settings, tmp_path):
|
|
"""Test 2: login_import_cookie - --import-cookie imports JSON."""
|
|
# Create temp cookie JSON file
|
|
cookie_file = tmp_path / "cookies.json"
|
|
cookie_file.write_text(json.dumps([
|
|
{"name": "z_c0", "value": "imported_value", "domain": ".zhihu.com"}
|
|
]))
|
|
|
|
with patch('kb_workflow.pipeline.config.get_settings', return_value=mock_settings), \
|
|
patch('kb_workflow.auth.cookie_manager.CookieManager') as MockManager, \
|
|
patch('kb_workflow.auth.cookie_manager.parse_json_cookies') as mock_parse:
|
|
|
|
mock_parse.return_value = "z_c0=imported_value"
|
|
mock_manager = MagicMock()
|
|
MockManager.return_value = mock_manager
|
|
|
|
# Act
|
|
result = login_command(import_cookie=str(cookie_file))
|
|
|
|
# Assert
|
|
assert result["success"] is True
|
|
assert "imported" in result["message"].lower()
|
|
mock_manager.save_cookie.assert_called_once_with("z_c0=imported_value")
|
|
|
|
def test_login_status_no_cookie(self, mock_settings):
|
|
"""Test 3a: login_status - --status with no cookie returns invalid."""
|
|
with patch('kb_workflow.pipeline.config.get_settings', return_value=mock_settings):
|
|
|
|
# Act
|
|
result = login_command(status=True)
|
|
|
|
# Assert
|
|
assert result["valid"] is False
|
|
assert "No cookie" in result["reason"]
|
|
|
|
def test_login_status_valid_cookie(
|
|
self, mock_settings_with_cookie, mock_validation_result_valid
|
|
):
|
|
"""Test 3b: login_status - --status with valid cookie returns user info."""
|
|
with patch('kb_workflow.pipeline.config.get_settings', return_value=mock_settings_with_cookie), \
|
|
patch('kb_workflow.kb_workflow.asyncio.run') as mock_run, \
|
|
patch('kb_workflow.auth.ZhihuLogin') as MockLogin:
|
|
|
|
# Setup mock - asyncio.run returns the result object directly
|
|
mock_login_instance = MagicMock()
|
|
MockLogin.return_value = mock_login_instance
|
|
mock_run.return_value = mock_validation_result_valid # Return object, not dict
|
|
|
|
# Act
|
|
result = login_command(status=True)
|
|
|
|
# Assert
|
|
assert result["valid"] is True
|
|
assert result["username"] == "TestUser"
|
|
assert result["user_id"] == "12345678"
|
|
|
|
def test_login_integration(
|
|
self, mock_settings, mock_login_result_success
|
|
):
|
|
"""Test 4: login_integration - Successful login saves cookie."""
|
|
with patch('kb_workflow.pipeline.config.get_settings', return_value=mock_settings), \
|
|
patch('kb_workflow.auth.cookie_manager.CookieManager') as MockManager, \
|
|
patch('kb_workflow.auth.ZhihuLogin') as MockLogin:
|
|
|
|
# Setup mock
|
|
mock_login_instance = MagicMock()
|
|
mock_login_instance.login_by_qrcode.return_value = mock_login_result_success
|
|
MockLogin.return_value = mock_login_instance
|
|
mock_manager = MagicMock()
|
|
MockManager.return_value = mock_manager
|
|
|
|
# Act
|
|
result = login_command()
|
|
|
|
# Assert - Cookie saved after successful login
|
|
assert result["success"] is True
|
|
mock_manager.save_cookie.assert_called_once_with(
|
|
mock_login_result_success.cookie_str
|
|
)
|
|
|
|
def test_login_error_handling(self, mock_settings):
|
|
"""Test 5: login handles exceptions gracefully."""
|
|
with patch('kb_workflow.pipeline.config.get_settings', side_effect=Exception("Config error")):
|
|
|
|
# Act
|
|
result = login_command()
|
|
|
|
# Assert
|
|
assert result["success"] is False
|
|
assert "Config error" in result["error"]
|