Skip to main content
Glama

MCP Atlassian

by ArconixForge
test_client_oauth.py17.5 kB
"""Tests for the ConfluenceClient with OAuth authentication.""" import os from unittest.mock import PropertyMock, patch import pytest from mcp_atlassian.confluence.client import ConfluenceClient from mcp_atlassian.confluence.config import ConfluenceConfig from mcp_atlassian.exceptions import MCPAtlassianAuthenticationError from mcp_atlassian.utils.oauth import BYOAccessTokenOAuthConfig, OAuthConfig class TestConfluenceClientOAuth: """Tests for ConfluenceClient with OAuth authentication.""" def test_init_with_oauth_config(self): """Test initializing the client with OAuth configuration.""" # Create a mock OAuth config oauth_config = OAuthConfig( client_id="test-client-id", client_secret="test-client-secret", redirect_uri="https://example.com/callback", scope="read:confluence-space.summary write:confluence-content", cloud_id="test-cloud-id", access_token="test-access-token", refresh_token="test-refresh-token", expires_at=9999999999.0, # Set a future expiry time ) # Create a Confluence config with OAuth config = ConfluenceConfig( url="https://test.atlassian.net/wiki", auth_type="oauth", oauth_config=oauth_config, ) # Mock dependencies with ( patch("mcp_atlassian.confluence.client.Confluence") as mock_confluence, patch( "mcp_atlassian.confluence.client.configure_oauth_session" ) as mock_configure_oauth, patch( "mcp_atlassian.confluence.client.configure_ssl_verification" ) as mock_configure_ssl, patch( "mcp_atlassian.preprocessing.confluence.ConfluencePreprocessor" ) as mock_preprocessor, patch.object( OAuthConfig, "is_token_expired", new_callable=PropertyMock, return_value=False, ) as mock_is_expired, patch.object( oauth_config, "ensure_valid_token", return_value=True ) as mock_ensure_valid, ): # Configure the mock to return success for OAuth configuration mock_configure_oauth.return_value = True # Initialize client client = ConfluenceClient(config=config) # Verify OAuth session configuration was called mock_configure_oauth.assert_called_once() # Verify Confluence was initialized with the expected parameters mock_confluence.assert_called_once() conf_kwargs = mock_confluence.call_args[1] assert ( conf_kwargs["url"] == f"https://api.atlassian.com/ex/confluence/{oauth_config.cloud_id}" ) assert "session" in conf_kwargs assert conf_kwargs["cloud"] is True # Verify SSL verification was configured mock_configure_ssl.assert_called_once() # Verify preprocessor was initialized assert client.preprocessor == mock_preprocessor.return_value def test_init_with_byo_access_token_oauth_config(self): """Test initializing the client with BYOAccessTokenOAuthConfig.""" # Create a mock BYO OAuth config byo_oauth_config = BYOAccessTokenOAuthConfig( cloud_id="test-byo-cloud-id", access_token="test-byo-access-token", ) # Create a Confluence config with BYO OAuth config = ConfluenceConfig( url="https://test.atlassian.net/wiki", auth_type="oauth", oauth_config=byo_oauth_config, ) # Mock dependencies with ( patch("mcp_atlassian.confluence.client.Confluence") as mock_confluence, patch( "mcp_atlassian.confluence.client.configure_oauth_session" ) as mock_configure_oauth, patch( "mcp_atlassian.confluence.client.configure_ssl_verification" ) as mock_configure_ssl, patch( "mcp_atlassian.preprocessing.confluence.ConfluencePreprocessor" ) as mock_preprocessor, ): # Configure the mock to return success for OAuth configuration mock_configure_oauth.return_value = True # Initialize client client = ConfluenceClient(config=config) # Verify OAuth session configuration was called mock_configure_oauth.assert_called_once() # Verify Confluence was initialized with the expected parameters mock_confluence.assert_called_once() conf_kwargs = mock_confluence.call_args[1] assert ( conf_kwargs["url"] == f"https://api.atlassian.com/ex/confluence/{byo_oauth_config.cloud_id}" ) assert "session" in conf_kwargs assert conf_kwargs["cloud"] is True # Verify SSL verification was configured mock_configure_ssl.assert_called_once() # Verify preprocessor was initialized assert client.preprocessor == mock_preprocessor.return_value def test_init_with_byo_oauth_missing_cloud_id(self): """Test initializing the client with BYO OAuth but missing cloud_id.""" # Create a mock BYO OAuth config without cloud_id byo_oauth_config = BYOAccessTokenOAuthConfig( access_token="test-byo-access-token", cloud_id="", # Explicitly empty or None ) # Create a Confluence config with BYO OAuth config = ConfluenceConfig( url="https://test.atlassian.net/wiki", auth_type="oauth", oauth_config=byo_oauth_config, ) # Verify error is raised by ConfluenceClient's validation with pytest.raises( ValueError, match="OAuth authentication requires a valid cloud_id" ): ConfluenceClient(config=config) def test_init_with_byo_oauth_failed_session_config(self): """Test initializing with BYO OAuth but failed session configuration.""" # Create a mock BYO OAuth config byo_oauth_config = BYOAccessTokenOAuthConfig( cloud_id="test-byo-cloud-id", access_token="test-byo-access-token", ) # Create a Confluence config with BYO OAuth config = ConfluenceConfig( url="https://test.atlassian.net/wiki", auth_type="oauth", oauth_config=byo_oauth_config, ) # Mock dependencies with OAuth configuration failure with patch( "mcp_atlassian.confluence.client.configure_oauth_session" ) as mock_configure_oauth: # Configure the mock to return failure for OAuth configuration mock_configure_oauth.return_value = False # Verify error is raised with pytest.raises( MCPAtlassianAuthenticationError, match="Failed to configure OAuth session", ): ConfluenceClient(config=config) def test_init_with_byo_oauth_empty_token_failed_session_config(self): """Test init with BYO OAuth, empty token, and failed session config.""" # Create a mock BYO OAuth config byo_oauth_config = BYOAccessTokenOAuthConfig( cloud_id="test-byo-cloud-id", access_token="", # Empty access token ) # Create a Confluence config with BYO OAuth config = ConfluenceConfig( url="https://test.atlassian.net/wiki", auth_type="oauth", oauth_config=byo_oauth_config, ) # Mock dependencies with OAuth configuration failure # configure_oauth_session might not even be called if token is validated earlier, # but if it is, it should fail. # For now, assume client init will fail due to invalid config before session setup, # or session setup fails because token is invalid. # The ConfluenceClient itself should raise error due to invalid oauth_config with patch( "mcp_atlassian.confluence.client.configure_oauth_session" ) as mock_configure_oauth: mock_configure_oauth.return_value = False # Assume it's called and fails with pytest.raises( MCPAtlassianAuthenticationError, # Or ValueError depending on where empty token is caught # For consistency with Jira, let's assume MCPAtlassianAuthenticationError if session config is attempted match="Failed to configure OAuth session", # This may change if validation is earlier ): ConfluenceClient(config=config) def test_init_with_oauth_missing_cloud_id(self): """Test initializing the client with OAuth but missing cloud_id.""" # Create a mock OAuth config without cloud_id oauth_config = OAuthConfig( client_id="test-client-id", client_secret="test-client-secret", redirect_uri="https://example.com/callback", scope="read:confluence-space.summary write:confluence-content", # No cloud_id access_token="test-access-token", ) # Create a Confluence config with OAuth config = ConfluenceConfig( url="https://test.atlassian.net/wiki", auth_type="oauth", oauth_config=oauth_config, ) # Verify error is raised with pytest.raises( ValueError, match="OAuth authentication requires a valid cloud_id" ): ConfluenceClient(config=config) def test_init_with_oauth_failed_session_config(self): """Test initializing the client with OAuth but failed session configuration.""" # Create a mock OAuth config oauth_config = OAuthConfig( client_id="test-client-id", client_secret="test-client-secret", redirect_uri="https://example.com/callback", scope="read:confluence-space.summary write:confluence-content", cloud_id="test-cloud-id", access_token="test-access-token", refresh_token="test-refresh-token", ) # Create a Confluence config with OAuth config = ConfluenceConfig( url="https://test.atlassian.net/wiki", auth_type="oauth", oauth_config=oauth_config, ) # Mock dependencies with OAuth configuration failure with ( patch( "mcp_atlassian.confluence.client.configure_oauth_session" ) as mock_configure_oauth, # Patch the methods directly on the instance, not the class patch.object( OAuthConfig, "is_token_expired", new_callable=PropertyMock, return_value=False, ) as mock_is_expired, patch.object( oauth_config, "ensure_valid_token", return_value=True ) as mock_ensure_valid, ): # Configure the mock to return failure for OAuth configuration mock_configure_oauth.return_value = False # Verify error is raised with pytest.raises( MCPAtlassianAuthenticationError, match="Failed to configure OAuth session", ): ConfluenceClient(config=config) def test_from_env_with_standard_oauth(self): """Test creating client from env vars with standard OAuth configuration.""" # Mock environment variables - NO CONFLUENCE_AUTH_TYPE env_vars = { "CONFLUENCE_URL": "https://test.atlassian.net/wiki", "CONFLUENCE_AUTH_TYPE": "oauth", "ATLASSIAN_OAUTH_CLIENT_ID": "env-client-id", "ATLASSIAN_OAUTH_CLIENT_SECRET": "env-client-secret", "ATLASSIAN_OAUTH_REDIRECT_URI": "https://example.com/callback", "ATLASSIAN_OAUTH_SCOPE": "read:confluence-space.summary", "ATLASSIAN_OAUTH_CLOUD_ID": "env-cloud-id", "ATLASSIAN_OAUTH_ACCESS_TOKEN": "env-access-token", # Needed by OAuthConfig "ATLASSIAN_OAUTH_REFRESH_TOKEN": "env-refresh-token", # Needed by OAuthConfig } # Mock OAuthConfig instance mock_standard_oauth_config = OAuthConfig( client_id="env-client-id", client_secret="env-client-secret", redirect_uri="https://example.com/callback", scope="read:confluence-space.summary", cloud_id="env-cloud-id", access_token="env-access-token", refresh_token="env-refresh-token", expires_at=9999999999.0, ) with ( patch.dict(os.environ, env_vars, clear=True), # Clear other env vars patch( "mcp_atlassian.confluence.config.get_oauth_config_from_env", # Patch the correct utility return_value=mock_standard_oauth_config, ), patch.object( OAuthConfig, "is_token_expired", new_callable=PropertyMock, return_value=False, ) as mock_is_expired_env, patch.object( mock_standard_oauth_config, "ensure_valid_token", return_value=True ) as mock_ensure_valid_env, patch("mcp_atlassian.confluence.client.Confluence") as mock_confluence, patch( "mcp_atlassian.confluence.client.configure_oauth_session", return_value=True, ) as mock_configure_oauth, patch( "mcp_atlassian.confluence.client.configure_ssl_verification" ) as mock_configure_ssl, ): # Initialize client from environment client = ConfluenceClient() # Calls ConfluenceConfig.from_env() internally # Verify client was initialized with OAuth assert client.config.auth_type == "oauth" assert client.config.oauth_config is mock_standard_oauth_config # Verify Confluence was initialized correctly mock_confluence.assert_called_once() conf_kwargs = mock_confluence.call_args[1] assert ( conf_kwargs["url"] == f"https://api.atlassian.com/ex/confluence/{mock_standard_oauth_config.cloud_id}" ) assert "session" in conf_kwargs assert conf_kwargs["cloud"] is True # Verify OAuth session was configured mock_configure_oauth.assert_called_once() def test_from_env_with_byo_token_oauth(self): """Test creating client from env vars with BYO token OAuth config.""" env_vars = { "CONFLUENCE_URL": "https://test.atlassian.net/wiki", "ATLASSIAN_OAUTH_ACCESS_TOKEN": "env-byo-access-token", "ATLASSIAN_OAUTH_CLOUD_ID": "env-byo-cloud-id", # No other OAuth vars needed for BYO if get_oauth_config_from_env handles it } mock_byo_oauth_config = BYOAccessTokenOAuthConfig( cloud_id="env-byo-cloud-id", access_token="env-byo-access-token" ) with ( patch.dict(os.environ, env_vars, clear=True), patch( "mcp_atlassian.confluence.config.get_oauth_config_from_env", return_value=mock_byo_oauth_config, ), patch("mcp_atlassian.confluence.client.Confluence") as mock_confluence, patch( "mcp_atlassian.confluence.client.configure_oauth_session", return_value=True, ) as mock_configure_oauth, patch( "mcp_atlassian.confluence.client.configure_ssl_verification" ) as mock_configure_ssl, ): client = ConfluenceClient() assert client.config.auth_type == "oauth" assert client.config.oauth_config is mock_byo_oauth_config mock_confluence.assert_called_once() conf_kwargs = mock_confluence.call_args[1] assert ( conf_kwargs["url"] == f"https://api.atlassian.com/ex/confluence/{mock_byo_oauth_config.cloud_id}" ) mock_configure_oauth.assert_called_once() def test_from_env_with_no_oauth_config_found(self): """Test client creation from env when no OAuth config is found by the utility.""" env_vars = { "CONFLUENCE_URL": "https://test.atlassian.net/wiki", # Deliberately missing other auth variables (basic, token, or complete OAuth) } with ( patch.dict(os.environ, env_vars, clear=True), patch( "mcp_atlassian.confluence.config.get_oauth_config_from_env", return_value=None, # Simulate no OAuth config found by the utility ), ): # ConfluenceConfig.from_env should raise ValueError if no auth can be determined with pytest.raises( ValueError, match="Cloud authentication requires CONFLUENCE_USERNAME and CONFLUENCE_API_TOKEN, or OAuth configuration", ): ConfluenceClient() # This will call ConfluenceConfig.from_env()

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/ArconixForge/mcp-atlassian'

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