Skip to main content
Glama
test_auth_setup.py10.9 kB
"""Tests for the auth_setup module.""" import argparse import json import os import tempfile import yaml from unittest.mock import patch, mock_open, MagicMock import pytest from imap_mcp.auth_setup import setup_gmail_oauth2, main @pytest.fixture def sample_config_file(): """Create a temporary config file with test data.""" config_data = { "imap": { "server": "imap.gmail.com", "port": 993, "username": "test@gmail.com" } } with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".yaml") as f: yaml.dump(config_data, f) temp_file_path = f.name yield temp_file_path # Clean up if os.path.exists(temp_file_path): os.unlink(temp_file_path) @pytest.fixture def sample_credentials_file(): """Create a temporary credentials file with test data.""" credentials_data = { "installed": { "client_id": "test_client_id.apps.googleusercontent.com", "client_secret": "test_client_secret", "redirect_uris": ["http://localhost", "urn:ietf:wg:oauth:2.0:oob"], "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", } } with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".json") as f: json.dump(credentials_data, f) temp_file_path = f.name yield temp_file_path # Clean up if os.path.exists(temp_file_path): os.unlink(temp_file_path) class TestSetupGmailOAuth2: """Tests for the setup_gmail_oauth2 function.""" @pytest.mark.skip(reason="Skipping test that requires real authentication") @patch("imap_mcp.auth_setup.get_authorization_url") @patch("imap_mcp.auth_setup.exchange_code_for_tokens") @patch("builtins.input", return_value="test_auth_code") def test_setup_gmail_oauth2_with_client_id_secret( self, mock_input, mock_exchange, mock_get_url ): """Test setup with client ID and secret provided.""" # Set up mocks mock_get_url.return_value = "https://example.com/auth" mock_exchange.return_value = ("test_access_token", "test_refresh_token", 3600) # Run the setup function result = setup_gmail_oauth2( client_id="test_client_id", client_secret="test_client_secret" ) # Verify the auth URL was generated mock_get_url.assert_called_once() # Verify user was prompted for the auth code mock_input.assert_called_once() # Verify the auth code was exchanged for tokens mock_exchange.assert_called_once_with( "test_auth_code", client_id="test_client_id", client_secret="test_client_secret" ) # Verify the returned config has the expected structure assert "imap" in result assert "oauth2" in result["imap"] assert result["imap"]["oauth2"]["refresh_token"] == "test_refresh_token" assert result["imap"]["oauth2"]["client_id"] == "test_client_id" assert result["imap"]["oauth2"]["client_secret"] == "test_client_secret" @pytest.mark.skip(reason="Skipping test that requires real authentication") @patch("imap_mcp.auth_setup.load_client_credentials") @patch("imap_mcp.auth_setup.get_authorization_url") @patch("imap_mcp.auth_setup.exchange_code_for_tokens") @patch("builtins.input", return_value="test_auth_code") def test_setup_gmail_oauth2_with_credentials_file( self, mock_input, mock_exchange, mock_get_url, mock_load, sample_credentials_file ): """Test setup with credentials file.""" # Set up mocks mock_load.return_value = ("file_client_id", "file_client_secret") mock_get_url.return_value = "https://example.com/auth" mock_exchange.return_value = ("test_access_token", "test_refresh_token", 3600) # Run the setup function result = setup_gmail_oauth2(credentials_file=sample_credentials_file) # Verify the credentials were loaded mock_load.assert_called_once_with(sample_credentials_file) # Verify the auth URL was generated with loaded credentials mock_get_url.assert_called_once() args = mock_get_url.call_args[1] assert args["client_id"] == "file_client_id" # Verify the returned config has the expected structure assert "imap" in result assert "oauth2" in result["imap"] assert result["imap"]["oauth2"]["refresh_token"] == "test_refresh_token" assert result["imap"]["oauth2"]["client_id"] == "file_client_id" @pytest.mark.skip(reason="Skipping test that requires authentication") @patch("imap_mcp.auth_setup.get_authorization_url") @patch("imap_mcp.auth_setup.exchange_code_for_tokens") @patch("builtins.input", return_value="test_auth_code") @patch("yaml.safe_load") def test_setup_gmail_oauth2_with_existing_config( self, mock_yaml_load, mock_input, mock_exchange, mock_get_url, sample_config_file ): """Test setup with existing config file.""" # Set up mocks mock_yaml_load.return_value = { "imap": { "server": "imap.gmail.com", "username": "existing@gmail.com" } } mock_get_url.return_value = "https://example.com/auth" mock_exchange.return_value = ("test_access_token", "test_refresh_token", 3600) # Run the setup function with patch("builtins.open", mock_open(read_data="")) as mock_file: result = setup_gmail_oauth2( client_id="test_client_id", client_secret="test_client_secret", config_path=sample_config_file ) # Verify the existing config was loaded mock_yaml_load.assert_called_once() # Verify the returned config preserves existing values assert "imap" in result assert "server" in result["imap"] assert result["imap"]["server"] == "imap.gmail.com" assert result["imap"]["username"] == "existing@gmail.com" # Verify new OAuth2 values were added assert "oauth2" in result["imap"] assert result["imap"]["oauth2"]["refresh_token"] == "test_refresh_token" @pytest.mark.skip(reason="Skipping test that requires authentication") @patch("imap_mcp.auth_setup.get_authorization_url") @patch("imap_mcp.auth_setup.exchange_code_for_tokens") @patch("builtins.input", return_value="test_auth_code") @patch("yaml.dump") def test_setup_gmail_oauth2_config_output( self, mock_yaml_dump, mock_input, mock_exchange, mock_get_url ): """Test writing config to output file.""" # Set up mocks mock_get_url.return_value = "https://example.com/auth" mock_exchange.return_value = ("test_access_token", "test_refresh_token", 3600) # Run the setup function with config output with patch("builtins.open", mock_open()) as mock_file: result = setup_gmail_oauth2( client_id="test_client_id", client_secret="test_client_secret", config_output="output_config.yaml" ) # Verify the file was opened for writing mock_file.assert_called_with("output_config.yaml", "w") # Verify yaml.dump was called with the expected config mock_yaml_dump.assert_called_once() args, kwargs = mock_yaml_dump.call_args assert "imap" in args[0] assert "oauth2" in args[0]["imap"] # Verify the file handle was passed to yaml.dump assert mock_file().write.called class TestMain: """Tests for the main function.""" @pytest.mark.skip(reason="Skipping test that requires authentication") @patch("imap_mcp.auth_setup.setup_gmail_oauth2") @patch("sys.argv") @patch("sys.exit") def test_main_success(self, mock_exit, mock_argv, mock_setup): """Test successful execution of main function.""" # Set up mocks mock_argv.__getitem__.side_effect = lambda i: [ "auth_setup.py", "--client-id", "test_client_id", "--client-secret", "test_client_secret", "--output", "output.yaml" ][i] mock_argv.__len__.return_value = 7 mock_setup.return_value = {"imap": {"oauth2": {"refresh_token": "test_token"}}} # Run the main function main() # Verify the setup function was called with the correct arguments mock_setup.assert_called_once_with( client_id="test_client_id", client_secret="test_client_secret", credentials_file=None, config_path=None, config_output="output.yaml" ) # Verify the program exits successfully mock_exit.assert_called_once_with(0) @pytest.mark.skip(reason="Skipping test that requires authentication") @patch("imap_mcp.auth_setup.setup_gmail_oauth2") @patch("sys.argv") @patch("sys.exit") def test_main_with_credentials_file(self, mock_exit, mock_argv, mock_setup): """Test main function with credentials file.""" # Set up mocks mock_argv.__getitem__.side_effect = lambda i: [ "auth_setup.py", "--credentials-file", "creds.json", "--config", "config.yaml", "--output", "output.yaml" ][i] mock_argv.__len__.return_value = 7 mock_setup.return_value = {"imap": {"oauth2": {"refresh_token": "test_token"}}} # Run the main function main() # Verify the setup function was called with the correct arguments mock_setup.assert_called_once_with( client_id=None, client_secret=None, credentials_file="creds.json", config_path="config.yaml", config_output="output.yaml" ) @pytest.mark.skip(reason="Skipping test that requires authentication") @patch("imap_mcp.auth_setup.setup_gmail_oauth2") @patch("sys.argv") @patch("sys.exit") def test_main_error(self, mock_exit, mock_argv, mock_setup): """Test main function with setup error.""" # Set up mocks mock_argv.__getitem__.side_effect = lambda i: [ "auth_setup.py", "--client-id", "test_client_id" ][i] mock_argv.__len__.return_value = 3 mock_setup.side_effect = ValueError("Test error") # Run the main function main() # Verify the program exits with error mock_exit.assert_called_once_with(1)

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/non-dirty/imap-mcp'

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