From 94c85baac9535ec33d898986d2cc0c668b44b257 Mon Sep 17 00:00:00 2001 From: starmen1265 Date: Tue, 17 Mar 2026 18:01:53 +0800 Subject: [PATCH] test(07-03): add failing tests for login CLI subcommand - Test login_default_mode - default QR code login flow - Test login_import_cookie - --import-cookie JSON import - Test login_status - --status cookie validation - Test login_integration - successful login saves cookie - Test login_error_handling - exception handling Co-Authored-By: Claude Opus 4.6 --- tests/test_auth/test_cli_login.py | 165 ++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 tests/test_auth/test_cli_login.py diff --git a/tests/test_auth/test_cli_login.py b/tests/test_auth/test_cli_login.py new file mode 100644 index 0000000..584277a --- /dev/null +++ b/tests/test_auth/test_cli_login.py @@ -0,0 +1,165 @@ +"""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.kb_workflow.get_settings', return_value=mock_settings), \ + patch('kb_workflow.kb_workflow.CookieManager') as MockManager, \ + patch('kb_workflow.kb_workflow.asyncio.run') as mock_run, \ + patch('kb_workflow.kb_workflow.ZhihuLogin') as MockLogin: + + # Setup mock + mock_run.return_value = mock_login_result_success.model_dump() + 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.kb_workflow.get_settings', return_value=mock_settings), \ + patch('kb_workflow.kb_workflow.CookieManager') as MockManager, \ + patch('kb_workflow.kb_workflow.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.kb_workflow.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.kb_workflow.get_settings', return_value=mock_settings_with_cookie), \ + patch('kb_workflow.kb_workflow.asyncio.run') as mock_run, \ + patch('kb_workflow.kb_workflow.ZhihuLogin') as MockLogin: + + # Setup mock + mock_login_instance = MagicMock() + MockLogin.return_value = mock_login_instance + mock_run.return_value = mock_validation_result_valid.model_dump() + + # 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.kb_workflow.get_settings', return_value=mock_settings), \ + patch('kb_workflow.kb_workflow.CookieManager') as MockManager, \ + patch('kb_workflow.kb_workflow.asyncio.run') as mock_run: + + # Setup mock + mock_run.return_value = mock_login_result_success.model_dump() + 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.kb_workflow.get_settings', side_effect=Exception("Config error")): + + # Act + result = login_command() + + # Assert + assert result["success"] is False + assert "Config error" in result["error"]