Skip to main content
Glama

Supabase MCP Server

Apache 2.0
797
  • Apple
  • Linux
test_sdk_client.py15.2 kB
import time import uuid from datetime import datetime from unittest.mock import AsyncMock, MagicMock, patch import pytest from supabase_mcp.clients.sdk_client import SupabaseSDKClient from supabase_mcp.exceptions import PythonSDKError from supabase_mcp.settings import Settings # Unique identifier for test users to avoid conflicts TEST_ID = f"test-{int(time.time())}-{uuid.uuid4().hex[:6]}" # Create unique test emails def get_test_email(prefix: str = "user"): """Generate a unique test email""" return f"a.zuev+{prefix}-{TEST_ID}@outlook.com" @pytest.mark.asyncio(loop_scope="module") class TestSDKClientIntegration: """ Unit tests for the SupabaseSDKClient. """ @pytest.fixture def mock_settings(self): """Create mock settings for testing.""" settings = MagicMock(spec=Settings) settings.supabase_project_ref = "test-project-ref" settings.supabase_service_role_key = "test-service-role-key" settings.supabase_region = "us-east-1" settings.supabase_url = "https://test-project-ref.supabase.co" return settings @pytest.fixture async def mock_sdk_client(self, mock_settings): """Create a mock SDK client for testing.""" # Reset singleton SupabaseSDKClient.reset() # Mock the Supabase client mock_supabase = MagicMock() mock_auth_admin = MagicMock() mock_supabase.auth.admin = mock_auth_admin # Mock the create_async_client function to return our mock client with patch('supabase_mcp.clients.sdk_client.create_async_client', return_value=mock_supabase): # Create client - this will now use our mocked create_async_client client = SupabaseSDKClient.get_instance(settings=mock_settings) # Manually set the client to ensure it's available client.client = mock_supabase return client async def test_list_users(self, mock_sdk_client: SupabaseSDKClient): """Test listing users with pagination""" # Mock user data mock_users = [ MagicMock(id="user1", email="user1@test.com", user_metadata={}), MagicMock(id="user2", email="user2@test.com", user_metadata={}) ] # Mock the list_users method as an async function mock_sdk_client.client.auth.admin.list_users = AsyncMock(return_value=mock_users) # Create test parameters list_params = {"page": 1, "per_page": 10} # List users result = await mock_sdk_client.call_auth_admin_method("list_users", list_params) # Verify response format assert result is not None assert hasattr(result, "__iter__") # Should be iterable (list of users) assert len(result) == 2 # Check that the first user has expected attributes first_user = result[0] assert hasattr(first_user, "id") assert hasattr(first_user, "email") assert hasattr(first_user, "user_metadata") # Test with invalid parameters - mock the validation error mock_sdk_client.client.auth.admin.list_users = AsyncMock(side_effect=Exception("Bad Pagination Parameters")) invalid_params = {"page": -1, "per_page": 10} with pytest.raises(PythonSDKError) as excinfo: await mock_sdk_client.call_auth_admin_method("list_users", invalid_params) assert "Bad Pagination Parameters" in str(excinfo.value) async def test_get_user_by_id(self, mock_sdk_client: SupabaseSDKClient): """Test retrieving a user by ID""" # Mock user data test_email = get_test_email("get") user_id = str(uuid.uuid4()) mock_user = MagicMock( id=user_id, email=test_email, user_metadata={"name": "Test User", "test_id": TEST_ID} ) mock_response = MagicMock(user=mock_user) # Mock the get_user_by_id method as an async function mock_sdk_client.client.auth.admin.get_user_by_id = AsyncMock(return_value=mock_response) # Get the user by ID get_params = {"uid": user_id} get_result = await mock_sdk_client.call_auth_admin_method("get_user_by_id", get_params) # Verify user data assert get_result is not None assert hasattr(get_result, "user") assert get_result.user.id == user_id assert get_result.user.email == test_email # Test with invalid parameters (non-existent user ID) mock_sdk_client.client.auth.admin.get_user_by_id = AsyncMock(side_effect=Exception("user_id must be an UUID")) invalid_params = {"uid": "non-existent-user-id"} with pytest.raises(PythonSDKError) as excinfo: await mock_sdk_client.call_auth_admin_method("get_user_by_id", invalid_params) assert "user_id must be an UUID" in str(excinfo.value) async def test_create_user(self, mock_sdk_client: SupabaseSDKClient): """Test creating a new user""" # Create a new test user test_email = get_test_email("create") user_id = str(uuid.uuid4()) mock_user = MagicMock( id=user_id, email=test_email, user_metadata={"name": "Test User", "test_id": TEST_ID} ) mock_response = MagicMock(user=mock_user) # Mock the create_user method as an async function mock_sdk_client.client.auth.admin.create_user = AsyncMock(return_value=mock_response) create_params = { "email": test_email, "password": f"Password123!{TEST_ID}", "email_confirm": True, "user_metadata": {"name": "Test User", "test_id": TEST_ID}, } # Create the user create_result = await mock_sdk_client.call_auth_admin_method("create_user", create_params) assert create_result is not None assert hasattr(create_result, "user") assert hasattr(create_result.user, "id") assert create_result.user.id == user_id # Test with invalid parameters (missing required fields) mock_sdk_client.client.auth.admin.create_user = AsyncMock(side_effect=Exception("Invalid parameters")) invalid_params = {"user_metadata": {"name": "Invalid User"}} with pytest.raises(PythonSDKError) as excinfo: await mock_sdk_client.call_auth_admin_method("create_user", invalid_params) assert "Invalid parameters" in str(excinfo.value) async def test_update_user_by_id(self, mock_sdk_client: SupabaseSDKClient): """Test updating a user's attributes""" # Mock user data test_email = get_test_email("update") user_id = str(uuid.uuid4()) mock_user = MagicMock( id=user_id, email=test_email, user_metadata={"email": "afterupdated@email.com"} ) mock_response = MagicMock(user=mock_user) # Mock the update_user_by_id method as an async function mock_sdk_client.client.auth.admin.update_user_by_id = AsyncMock(return_value=mock_response) # Update the user update_params = { "uid": user_id, "attributes": { "user_metadata": { "email": "afterupdated@email.com", } }, } update_result = await mock_sdk_client.call_auth_admin_method("update_user_by_id", update_params) # Verify user was updated assert update_result is not None assert hasattr(update_result, "user") assert update_result.user.id == user_id assert update_result.user.user_metadata["email"] == "afterupdated@email.com" # Test with invalid parameters (non-existent user ID) mock_sdk_client.client.auth.admin.update_user_by_id = AsyncMock(side_effect=Exception("user_id must be an uuid")) invalid_params = { "uid": "non-existent-user-id", "attributes": {"user_metadata": {"name": "Invalid Update"}}, } with pytest.raises(PythonSDKError) as excinfo: await mock_sdk_client.call_auth_admin_method("update_user_by_id", invalid_params) assert "user_id must be an uuid" in str(excinfo.value).lower() async def test_delete_user(self, mock_sdk_client: SupabaseSDKClient): """Test deleting a user""" # Mock user data user_id = str(uuid.uuid4()) # Mock the delete_user method as an async function to return None (success) mock_sdk_client.client.auth.admin.delete_user = AsyncMock(return_value=None) # Delete the user delete_params = {"id": user_id} # The delete_user method returns None on success result = await mock_sdk_client.call_auth_admin_method("delete_user", delete_params) assert result is None # Test with invalid parameters (non-UUID format user ID) mock_sdk_client.client.auth.admin.delete_user = AsyncMock(side_effect=Exception("user_id must be an uuid")) invalid_params = {"id": "non-existent-user-id"} with pytest.raises(PythonSDKError) as excinfo: await mock_sdk_client.call_auth_admin_method("delete_user", invalid_params) assert "user_id must be an uuid" in str(excinfo.value).lower() async def test_invite_user_by_email(self, mock_sdk_client: SupabaseSDKClient): """Test inviting a user by email""" # Mock user data test_email = get_test_email("invite") user_id = str(uuid.uuid4()) mock_user = MagicMock( id=user_id, email=test_email, invited_at=datetime.now().isoformat() ) mock_response = MagicMock(user=mock_user) # Mock the invite_user_by_email method as an async function mock_sdk_client.client.auth.admin.invite_user_by_email = AsyncMock(return_value=mock_response) # Create invite parameters invite_params = { "email": test_email, "options": {"data": {"name": "Invited User", "test_id": TEST_ID, "invited_at": datetime.now().isoformat()}}, } # Invite the user result = await mock_sdk_client.call_auth_admin_method("invite_user_by_email", invite_params) # Verify response assert result is not None assert hasattr(result, "user") assert result.user.email == test_email assert hasattr(result.user, "invited_at") # Test with invalid parameters (missing email) mock_sdk_client.client.auth.admin.invite_user_by_email = AsyncMock(side_effect=Exception("Invalid parameters")) invalid_params = {"options": {"data": {"name": "Invalid Invite"}}} with pytest.raises(PythonSDKError) as excinfo: await mock_sdk_client.call_auth_admin_method("invite_user_by_email", invalid_params) assert "Invalid parameters" in str(excinfo.value) async def test_generate_link(self, mock_sdk_client: SupabaseSDKClient): """Test generating authentication links""" # Mock response for generate_link mock_properties = MagicMock(action_link="https://example.com/auth/link") mock_response = MagicMock(properties=mock_properties) # Mock the generate_link method as an async function mock_sdk_client.client.auth.admin.generate_link = AsyncMock(return_value=mock_response) # Test signup link link_params = { "type": "signup", "email": get_test_email("signup"), "password": f"Password123!{TEST_ID}", "options": { "data": {"name": "Signup User", "test_id": TEST_ID}, "redirect_to": "https://example.com/welcome", }, } # Generate link result = await mock_sdk_client.call_auth_admin_method("generate_link", link_params) # Verify response assert result is not None assert hasattr(result, "properties") assert hasattr(result.properties, "action_link") # Test with invalid parameters (invalid link type) mock_sdk_client.client.auth.admin.generate_link = AsyncMock(side_effect=Exception("Invalid parameters")) invalid_params = {"type": "invalid_type", "email": get_test_email("invalid")} with pytest.raises(PythonSDKError) as excinfo: await mock_sdk_client.call_auth_admin_method("generate_link", invalid_params) assert "Invalid parameters" in str(excinfo.value) or "invalid type" in str(excinfo.value).lower() async def test_delete_factor(self, mock_sdk_client: SupabaseSDKClient): """Test deleting an MFA factor""" # Mock the delete_factor method as an async function to raise not implemented mock_sdk_client.client.auth.admin.delete_factor = AsyncMock(side_effect=AttributeError("method not found")) # Attempt to delete a factor delete_factor_params = {"user_id": str(uuid.uuid4()), "id": "non-existent-factor-id"} with pytest.raises(PythonSDKError) as excinfo: await mock_sdk_client.call_auth_admin_method("delete_factor", delete_factor_params) # We expect this to fail with a specific error message assert "not implemented" in str(excinfo.value).lower() or "method not found" in str(excinfo.value).lower() async def test_empty_parameters(self, mock_sdk_client: SupabaseSDKClient): """Test validation errors with empty parameters for various methods""" # Test methods with empty parameters methods = ["get_user_by_id", "create_user", "update_user_by_id", "delete_user", "generate_link"] for method in methods: empty_params = {} # Mock the method to raise validation error setattr(mock_sdk_client.client.auth.admin, method, AsyncMock(side_effect=Exception("Invalid parameters"))) # Should raise PythonSDKError containing validation error details with pytest.raises(PythonSDKError) as excinfo: await mock_sdk_client.call_auth_admin_method(method, empty_params) # Verify error message contains validation details assert "Invalid parameters" in str(excinfo.value) or "validation error" in str(excinfo.value).lower() async def test_client_without_service_role_key(self, mock_settings): """Test that an exception is raised when attempting to use the SDK client without a service role key.""" # Create settings without service role key mock_settings.supabase_service_role_key = None # Reset singleton SupabaseSDKClient.reset() # Create client client = SupabaseSDKClient.get_instance(settings=mock_settings) # Attempt to call a method - should raise an exception with pytest.raises(PythonSDKError) as excinfo: await client.call_auth_admin_method("list_users", {}) assert "service role key is not configured" in str(excinfo.value)

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/alexander-zuev/supabase-mcp-server'

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