We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/davidteren/play-sound-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
"""
Tests for configuration management.
"""
import os
import pytest
from pathlib import Path
from unittest.mock import patch
from mcp_server_play_sound.config import ServerConfig, ConfigurationError
class TestServerConfig:
"""Test ServerConfig functionality."""
def test_default_config(self):
"""Test default configuration values."""
config = ServerConfig()
assert config.custom_sound_path is None
assert config.volume_level == 0.8
assert config.enable_fallback is True
assert config.max_file_size_mb == 10
assert config.playback_timeout_seconds == 30
assert config.audio_backend == "auto"
assert config.enable_audio_cache is True
assert config.cache_size_limit == 5
assert config.restrict_to_user_home is True
assert '.wav' in config.allowed_audio_extensions
assert '.mp3' in config.allowed_audio_extensions
def test_from_environment_defaults(self):
"""Test loading from environment with no variables set."""
with patch.dict(os.environ, {}, clear=True):
config = ServerConfig.from_environment()
assert config.custom_sound_path is None
assert config.volume_level == 0.8
assert config.enable_fallback is True
def test_from_environment_custom_values(self):
"""Test loading custom values from environment."""
env_vars = {
'VOLUME_LEVEL': '0.5',
'ENABLE_FALLBACK': 'false',
'MAX_FILE_SIZE_MB': '20',
'PLAYBACK_TIMEOUT_SECONDS': '60',
'AUDIO_BACKEND': 'simpleaudio',
'ENABLE_AUDIO_CACHE': 'false',
'CACHE_SIZE_LIMIT': '10',
'RESTRICT_TO_USER_HOME': 'false',
}
with patch.dict(os.environ, env_vars, clear=True):
config = ServerConfig.from_environment()
assert config.volume_level == 0.5
assert config.enable_fallback is False
assert config.max_file_size_mb == 20
assert config.playback_timeout_seconds == 60
assert config.audio_backend == 'simpleaudio'
assert config.enable_audio_cache is False
assert config.cache_size_limit == 10
assert config.restrict_to_user_home is False
def test_parse_bool_values(self):
"""Test boolean parsing from environment variables."""
# Test true values
for true_val in ['true', '1', 'yes', 'on', 'TRUE', 'Yes', 'ON']:
assert ServerConfig._parse_bool('TEST', None) is None # Default when not set
with patch.dict(os.environ, {'TEST_VAR': true_val}):
assert ServerConfig._parse_bool('TEST_VAR', False) is True
# Test false values
for false_val in ['false', '0', 'no', 'off', 'FALSE', 'No', 'OFF']:
with patch.dict(os.environ, {'TEST_VAR': false_val}):
assert ServerConfig._parse_bool('TEST_VAR', True) is False
def test_parse_bool_invalid(self):
"""Test invalid boolean values raise errors."""
with patch.dict(os.environ, {'TEST_VAR': 'invalid'}):
with pytest.raises(ConfigurationError, match="must be a boolean value"):
ServerConfig._parse_bool('TEST_VAR', False)
def test_parse_float_invalid(self):
"""Test invalid float values raise errors."""
with patch.dict(os.environ, {'TEST_VAR': 'not_a_float'}):
with pytest.raises(ConfigurationError, match="must be a valid float"):
ServerConfig._parse_float('TEST_VAR', 0.5)
def test_parse_int_invalid(self):
"""Test invalid integer values raise errors."""
with patch.dict(os.environ, {'TEST_VAR': 'not_an_int'}):
with pytest.raises(ConfigurationError, match="must be a valid integer"):
ServerConfig._parse_int('TEST_VAR', 10)
def test_parse_extensions(self):
"""Test parsing file extensions."""
with patch.dict(os.environ, {'TEST_VAR': 'wav,mp3,.flac,ogg'}):
extensions = ServerConfig._parse_extensions('TEST_VAR')
expected = {'.wav', '.mp3', '.flac', '.ogg'}
assert extensions == expected
def test_validate_volume_level(self):
"""Test volume level validation."""
# Valid volume levels
for volume in [0.0, 0.5, 1.0]:
config = ServerConfig(volume_level=volume)
config._validate_volume_level() # Should not raise
# Invalid volume levels
for volume in [-0.1, 1.1, 2.0]:
config = ServerConfig(volume_level=volume)
with pytest.raises(ConfigurationError, match="VOLUME_LEVEL must be between 0.0 and 1.0"):
config._validate_volume_level()
def test_validate_numeric_ranges(self):
"""Test numeric range validation."""
# Test max_file_size_mb
config = ServerConfig(max_file_size_mb=0)
with pytest.raises(ConfigurationError, match="MAX_FILE_SIZE_MB must be between 1 and 100"):
config._validate_numeric_ranges()
config = ServerConfig(max_file_size_mb=101)
with pytest.raises(ConfigurationError, match="MAX_FILE_SIZE_MB must be between 1 and 100"):
config._validate_numeric_ranges()
# Test playback_timeout_seconds
config = ServerConfig(playback_timeout_seconds=0)
with pytest.raises(ConfigurationError, match="PLAYBACK_TIMEOUT_SECONDS must be between 1 and 300"):
config._validate_numeric_ranges()
config = ServerConfig(playback_timeout_seconds=301)
with pytest.raises(ConfigurationError, match="PLAYBACK_TIMEOUT_SECONDS must be between 1 and 300"):
config._validate_numeric_ranges()
def test_validate_audio_backend(self):
"""Test audio backend validation."""
# Valid backends
for backend in ['auto', 'simpleaudio', 'pydub', 'system']:
config = ServerConfig(audio_backend=backend)
config._validate_audio_backend() # Should not raise
# Invalid backend
config = ServerConfig(audio_backend='invalid')
with pytest.raises(ConfigurationError, match="AUDIO_BACKEND must be one of"):
config._validate_audio_backend()
def test_validate_security_settings(self):
"""Test security settings validation."""
# Invalid extension (no dot)
config = ServerConfig(allowed_audio_extensions={'wav'})
with pytest.raises(ConfigurationError, match="Audio extensions must start with"):
config._validate_security_settings()
# Invalid extension (too short)
config = ServerConfig(allowed_audio_extensions={'.'})
with pytest.raises(ConfigurationError, match="Audio extensions must have at least one character"):
config._validate_security_settings()
def test_full_validation(self):
"""Test complete configuration validation."""
config = ServerConfig.from_environment()
config.validate() # Should not raise with default values