"""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"]