Skip to main content
Glama
test_config.py12.8 kB
"""Tests for the config module.""" import tempfile from pathlib import Path from unittest.mock import patch import pytest import yaml from imap_mcp.config import ImapConfig, ServerConfig, load_config class TestImapConfig: """Test cases for the ImapConfig class.""" def test_init(self): """Test ImapConfig initialization.""" config = ImapConfig( host="imap.example.com", port=993, username="test@example.com", password="password" ) assert config.host == "imap.example.com" assert config.port == 993 assert config.username == "test@example.com" assert config.password == "password" assert config.use_ssl is True # Default value # Test with custom SSL setting config = ImapConfig( host="imap.example.com", port=143, username="test@example.com", password="password", use_ssl=False ) assert config.use_ssl is False def test_from_dict(self): """Test creating ImapConfig from a dictionary.""" data = { "host": "imap.example.com", "port": 993, "username": "test@example.com", "password": "password", "use_ssl": True } config = ImapConfig.from_dict(data) assert config.host == "imap.example.com" assert config.port == 993 assert config.username == "test@example.com" assert config.password == "password" assert config.use_ssl is True # Test with minimal data and defaults minimal_data = { "host": "imap.example.com", "username": "test@example.com", "password": "password" } config = ImapConfig.from_dict(minimal_data) assert config.host == "imap.example.com" assert config.port == 993 # Default with SSL assert config.username == "test@example.com" assert config.password == "password" assert config.use_ssl is True # Default # Test with non-SSL port default non_ssl_data = { "host": "imap.example.com", "username": "test@example.com", "password": "password", "use_ssl": False } config = ImapConfig.from_dict(non_ssl_data) assert config.port == 143 # Default non-SSL port def test_from_dict_with_env_password(self, monkeypatch): """Test creating ImapConfig with password from environment variable.""" # Set environment variable monkeypatch.setenv("IMAP_PASSWORD", "env_password") data = { "host": "imap.example.com", "username": "test@example.com", # No password in dict } config = ImapConfig.from_dict(data) assert config.password == "env_password" # Test that dict password takes precedence data_with_password = { "host": "imap.example.com", "username": "test@example.com", "password": "dict_password" } config = ImapConfig.from_dict(data_with_password) assert config.password == "dict_password" def test_from_dict_missing_password(self, monkeypatch): """Test error when password is missing from both dict and environment.""" # Ensure environment variable is not set monkeypatch.delenv("IMAP_PASSWORD", raising=False) data = { "host": "imap.example.com", "username": "test@example.com", # No password } with pytest.raises(ValueError) as excinfo: ImapConfig.from_dict(data) assert "IMAP password must be specified" in str(excinfo.value) def test_from_dict_missing_required_fields(self): """Test error when required fields are missing.""" # Missing host with pytest.raises(KeyError): ImapConfig.from_dict({"username": "test@example.com", "password": "password"}) # Missing username with pytest.raises(KeyError): ImapConfig.from_dict({"host": "imap.example.com", "password": "password"}) class TestServerConfig: """Test cases for the ServerConfig class.""" def test_init(self): """Test ServerConfig initialization.""" imap_config = ImapConfig( host="imap.example.com", port=993, username="test@example.com", password="password" ) # Test without allowed folders server_config = ServerConfig(imap=imap_config) assert server_config.imap == imap_config assert server_config.allowed_folders is None # Test with allowed folders allowed_folders = ["INBOX", "Sent", "Archive"] server_config = ServerConfig(imap=imap_config, allowed_folders=allowed_folders) assert server_config.imap == imap_config assert server_config.allowed_folders == allowed_folders def test_from_dict(self, monkeypatch): """Test creating ServerConfig from a dictionary.""" data = { "imap": { "host": "imap.example.com", "port": 993, "username": "test@example.com", "password": "password" }, "allowed_folders": ["INBOX", "Sent"] } config = ServerConfig.from_dict(data) assert config.imap.host == "imap.example.com" assert config.imap.port == 993 assert config.imap.username == "test@example.com" assert config.imap.password == "password" assert config.allowed_folders == ["INBOX", "Sent"] # Test with minimal data (no allowed_folders) minimal_data = { "imap": { "host": "imap.example.com", "username": "test@example.com", "password": "password" } } config = ServerConfig.from_dict(minimal_data) assert config.imap.host == "imap.example.com" assert config.allowed_folders is None # Test with empty dict (needs env password) monkeypatch.setenv("IMAP_PASSWORD", "env_password") with pytest.raises(KeyError): # Should fail because host is required ServerConfig.from_dict({}) class TestLoadConfig: """Test cases for the load_config function.""" def test_load_from_file(self): """Test loading configuration from a file.""" config_data = { "imap": { "host": "imap.example.com", "port": 993, "username": "test@example.com", "password": "password" }, "allowed_folders": ["INBOX", "Sent"] } # Create temporary config file with tempfile.NamedTemporaryFile(suffix=".yaml", mode="w+") as temp_file: yaml.dump(config_data, temp_file) temp_file.flush() # Load config from the temp file config = load_config(temp_file.name) # Verify config data assert config.imap.host == "imap.example.com" assert config.imap.port == 993 assert config.imap.username == "test@example.com" assert config.imap.password == "password" assert config.allowed_folders == ["INBOX", "Sent"] def test_load_from_default_locations(self, monkeypatch, tmp_path): """Test loading configuration from default locations.""" # Clear any environment variables that might affect the test for env_var in [ "IMAP_HOST", "IMAP_PORT", "IMAP_USERNAME", "IMAP_PASSWORD", "IMAP_USE_SSL", "IMAP_ALLOWED_FOLDERS" ]: monkeypatch.delenv(env_var, raising=False) config_data = { "imap": { "host": "imap.example.com", "username": "test@example.com", "password": "password" } } # Create a temporary config file in one of the default locations temp_dir = tmp_path / ".config" / "imap-mcp" temp_dir.mkdir(parents=True, exist_ok=True) temp_file = temp_dir / "config.yaml" with open(temp_file, "w") as f: yaml.dump(config_data, f) # Monkeypatch Path.expanduser to return our temp path original_expanduser = Path.expanduser def mock_expanduser(self): if str(self) == "~/.config/imap-mcp/config.yaml": return temp_file return original_expanduser(self) monkeypatch.setattr(Path, "expanduser", mock_expanduser) # Monkeypatch to ensure no other config file is found def mock_exists(path): if path == temp_file: return True return False monkeypatch.setattr(Path, "exists", mock_exists) # Load config without specifying path (should find default) config = load_config() # Verify config data assert config.imap.host == "imap.example.com" assert config.imap.username == "test@example.com" assert config.imap.password == "password" def test_load_from_env_variables(self, monkeypatch): """Test loading configuration from environment variables.""" # Set environment variables monkeypatch.setenv("IMAP_HOST", "imap.example.com") monkeypatch.setenv("IMAP_PORT", "993") monkeypatch.setenv("IMAP_USERNAME", "test@example.com") monkeypatch.setenv("IMAP_PASSWORD", "env_password") monkeypatch.setenv("IMAP_USE_SSL", "true") monkeypatch.setenv("IMAP_ALLOWED_FOLDERS", "INBOX,Sent,Archive") # Mock open to raise FileNotFoundError original_open = open def mock_open(*args, **kwargs): if args[0] == "nonexistent_file.yaml": raise FileNotFoundError(f"No such file: {args[0]}") return original_open(*args, **kwargs) # Need to patch the built-in open function with patch("builtins.open", side_effect=mock_open): # Load config (will use env variables since file doesn't exist) config = load_config("nonexistent_file.yaml") # Verify config data assert config.imap.host == "imap.example.com" assert config.imap.port == 993 assert config.imap.username == "test@example.com" assert config.imap.password == "env_password" assert config.imap.use_ssl is True assert config.allowed_folders == ["INBOX", "Sent", "Archive"] # Test with non-SSL setting monkeypatch.setenv("IMAP_USE_SSL", "false") config = load_config("nonexistent_file.yaml") assert config.imap.use_ssl is False def test_load_missing_required_env(self, monkeypatch): """Test error when required environment variables are missing.""" # Ensure IMAP_HOST is not set monkeypatch.delenv("IMAP_HOST", raising=False) # Mock open to raise FileNotFoundError original_open = open def mock_open(*args, **kwargs): if args[0] == "nonexistent_file.yaml": raise FileNotFoundError(f"No such file: {args[0]}") return original_open(*args, **kwargs) # Need to patch the built-in open function with patch("builtins.open", side_effect=mock_open): with pytest.raises(ValueError) as excinfo: load_config("nonexistent_file.yaml") assert "IMAP_HOST environment variable not set" in str(excinfo.value) def test_invalid_config(self): """Test error when config is invalid.""" # Create a config file with invalid data config_data = { "imap": { # Missing required host "username": "test@example.com", "password": "password" } } # Create temporary config file with tempfile.NamedTemporaryFile(suffix=".yaml", mode="w+") as temp_file: yaml.dump(config_data, temp_file) temp_file.flush() # Load should raise ValueError with pytest.raises(ValueError) as excinfo: load_config(temp_file.name) assert "Missing required configuration" in str(excinfo.value)

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