Skip to main content
Glama

Finizi B4B MCP Server

by hqtrung
test_auth.py9.5 kB
"""Comprehensive tests for authentication functionality.""" import json import pytest from unittest.mock import Mock, AsyncMock, patch, MagicMock import httpx from src.finizi_b4b_mcp.tools.auth import login, logout, whoami from src.finizi_b4b_mcp.auth.token_handler import extract_user_token from src.finizi_b4b_mcp.utils.errors import MCPAuthenticationError # Load mock responses with open("tests/fixtures/mock_responses.json") as f: MOCK_RESPONSES = json.load(f) # Tests for extract_user_token function @pytest.mark.asyncio async def test_extract_token_success(): """Test successful token extraction from session.""" ctx = MagicMock() ctx.session.metadata = {"user_token": "valid_jwt_token"} token = await extract_user_token(ctx) assert token == "valid_jwt_token" @pytest.mark.asyncio async def test_extract_token_not_authenticated(): """Test token extraction error when not authenticated.""" ctx = MagicMock() ctx.session.metadata = {} with pytest.raises(MCPAuthenticationError) as exc_info: await extract_user_token(ctx) # Updated to match actual error message from token_handler.py assert "No authentication session found" in str(exc_info.value) or "Authentication token is missing" in str(exc_info.value) @pytest.mark.asyncio async def test_extract_token_missing_session(): """Test error when session is missing.""" ctx = MagicMock() ctx.session = None with pytest.raises(MCPAuthenticationError) as exc_info: await extract_user_token(ctx) assert "No authentication session found" in str(exc_info.value) @pytest.mark.asyncio async def test_extract_token_strips_whitespace(): """Test that token is stripped of whitespace.""" ctx = MagicMock() ctx.session.metadata = {"user_token": " token_with_spaces "} token = await extract_user_token(ctx) assert token == "token_with_spaces" @pytest.mark.asyncio async def test_extract_token_empty_string(): """Test error when token is empty string.""" ctx = MagicMock() ctx.session.metadata = {"user_token": " "} with pytest.raises(MCPAuthenticationError) as exc_info: await extract_user_token(ctx) assert "Authentication token cannot be empty" in str(exc_info.value) @pytest.mark.asyncio async def test_extract_token_invalid_type(): """Test error when token is not a string.""" ctx = MagicMock() ctx.session.metadata = {"user_token": 12345} with pytest.raises(MCPAuthenticationError) as exc_info: await extract_user_token(ctx) assert "Authentication token must be a string" in str(exc_info.value) # Tests for login function @pytest.mark.asyncio async def test_login_success(): """Test successful login with valid credentials.""" # Mock context ctx = Mock() ctx.session = Mock() ctx.session.metadata = {} # Mock response mock_response = Mock() mock_response.status_code = 200 mock_response.json.return_value = MOCK_RESPONSES["auth"]["login_success"] # Mock HTTP client mock_http_client = AsyncMock() mock_http_client.post = AsyncMock(return_value=mock_response) with patch('src.finizi_b4b_mcp.tools.auth.get_api_client') as mock_get_client: mock_api_client = Mock() mock_api_client._get_client = AsyncMock(return_value=mock_http_client) mock_get_client.return_value = mock_api_client result = await login("+84909495665", "Admin123@", ctx) # Verify result assert result["success"] is True assert "Successfully logged in" in result["message"] assert result["email"] == "test@finizi.ai" assert result["is_super_admin"] is False # Verify token storage assert ctx.session.metadata["user_token"] == "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test_token" assert ctx.session.metadata["refresh_token"] == "refresh_token_test" assert ctx.session.metadata["user_email"] == "test@finizi.ai" assert ctx.session.metadata["is_super_admin"] is False @pytest.mark.asyncio async def test_login_invalid_credentials(): """Test login with invalid credentials returns 401 error.""" ctx = Mock() ctx.session = Mock() ctx.session.metadata = {} # Mock 401 response mock_response = Mock() mock_response.status_code = 401 mock_response.json.return_value = MOCK_RESPONSES["auth"]["login_failure"] mock_response.text = "Unauthorized" mock_http_client = AsyncMock() mock_http_client.post = AsyncMock(side_effect=httpx.HTTPStatusError( "Unauthorized", request=Mock(), response=mock_response )) with patch('src.finizi_b4b_mcp.tools.auth.get_api_client') as mock_get_client: mock_api_client = Mock() mock_api_client._get_client = AsyncMock(return_value=mock_http_client) mock_get_client.return_value = mock_api_client result = await login("+84909495665", "WrongPassword", ctx) assert result["success"] is False assert "Login failed" in result["error"] assert "Invalid credentials" in result["error"] @pytest.mark.asyncio async def test_login_network_error(): """Test login handles network errors gracefully.""" ctx = Mock() ctx.session = Mock() ctx.session.metadata = {} mock_http_client = AsyncMock() mock_http_client.post = AsyncMock(side_effect=httpx.ConnectError("Connection failed")) with patch('src.finizi_b4b_mcp.tools.auth.get_api_client') as mock_get_client: mock_api_client = Mock() mock_api_client._get_client = AsyncMock(return_value=mock_http_client) mock_get_client.return_value = mock_api_client result = await login("+84909495665", "Admin123@", ctx) assert result["success"] is False assert "Unexpected error during login" in result["error"] # Tests for logout function @pytest.mark.asyncio async def test_logout(): """Test logout clears session metadata.""" ctx = Mock() ctx.session = Mock() ctx.session.metadata = { "user_token": "test_token", "refresh_token": "refresh_token", "user_email": "test@finizi.ai", "user_id": "user-123" } result = await logout(ctx) assert result["success"] is True assert "Successfully logged out" in result["message"] assert "test@finizi.ai" in result["message"] assert len(ctx.session.metadata) == 0 @pytest.mark.asyncio async def test_logout_error_handling(): """Test logout handles errors gracefully.""" ctx = Mock() ctx.session = Mock() ctx.session.metadata = Mock() ctx.session.metadata.get.side_effect = Exception("Unexpected error") result = await logout(ctx) assert result["success"] is False assert "Error during logout" in result["error"] # Tests for whoami function @pytest.mark.asyncio async def test_whoami_success(): """Test getting user info when authenticated.""" ctx = Mock() ctx.session = Mock() ctx.session.metadata = {"user_token": "valid_token"} mock_response = MOCK_RESPONSES["auth"]["whoami_success"] with patch('src.finizi_b4b_mcp.tools.auth.get_api_client') as mock_get_client: mock_api_client = Mock() mock_api_client.get = AsyncMock(return_value=mock_response) mock_get_client.return_value = mock_api_client result = await whoami(ctx) assert result["success"] is True assert result["user"]["email"] == "test@finizi.ai" assert result["user"]["phone"] == "+84909495665" assert result["user"]["is_super_admin"] is False @pytest.mark.asyncio async def test_whoami_not_authenticated(): """Test whoami returns error when not authenticated.""" ctx = Mock() ctx.session = Mock() ctx.session.metadata = {} result = await whoami(ctx) # Updated to match actual error format from auth.py whoami function # The error is wrapped in "Unexpected error" with MCPAuthenticationError message assert result["success"] is False assert "error" in result assert ("authentication" in result["error"].lower() or "not authenticated" in result["error"].lower()) @pytest.mark.asyncio async def test_whoami_http_error(): """Test whoami handles HTTP errors.""" ctx = Mock() ctx.session = Mock() ctx.session.metadata = {"user_token": "invalid_token"} mock_response = Mock() mock_response.status_code = 401 with patch('src.finizi_b4b_mcp.tools.auth.get_api_client') as mock_get_client: mock_api_client = Mock() mock_api_client.get = AsyncMock(side_effect=httpx.HTTPStatusError( "Unauthorized", request=Mock(), response=mock_response )) mock_get_client.return_value = mock_api_client result = await whoami(ctx) assert result["success"] is False assert "Failed to get user info" in result["error"] @pytest.mark.asyncio async def test_whoami_unexpected_error(): """Test whoami handles unexpected errors.""" ctx = Mock() ctx.session = Mock() ctx.session.metadata = {"user_token": "valid_token"} with patch('src.finizi_b4b_mcp.tools.auth.get_api_client') as mock_get_client: mock_api_client = Mock() mock_api_client.get = AsyncMock(side_effect=Exception("Unexpected error")) mock_get_client.return_value = mock_api_client result = await whoami(ctx) assert result["success"] is False assert "Unexpected error" in result["error"]

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/hqtrung/finizi-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server