Files
mcp-synology-container/tests/test_config.py
T
marcus 661460bfd9 fix: v0.2.9 — review welle 1 (C-1, C-2, M-3)
C-1: __version__ now derived from package metadata via
importlib.metadata.version() so pyproject.toml is the single source of
truth. Previously stuck at "0.1.0" since the initial release.

C-2: Backfill CHANGELOG entries for 0.2.7 and 0.2.8 (both releases had
shipped without changelog updates) and add a 0.2.9 entry covering this
welle.

M-3: Reject project names containing path separators or other unsafe
characters before they reach _find_compose_path. Previously a name like
"../../etc" could traverse out of compose_base_path when the project was
not yet registered with Container Manager. Adds _validate_project_name
(regex ^[a-zA-Z0-9_-]+$, applied in read_compose, update_compose,
update_image_tag, update_env_var) plus parametrized tests for valid and
unsafe names and one rejection test per tool. 236 tests pass.

Also: ruff format autofix on three pre-existing files (cli.py,
config.py, test_config.py) — cosmetic only.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-18 09:07:00 +02:00

168 lines
4.8 KiB
Python

"""Tests for config.py."""
import pytest
import yaml
from mcp_synology_container.config import (
AppConfig,
ConnectionConfig,
_merge_env_overrides,
_validate_config,
load_config,
save_config,
)
def test_validate_config_minimal():
raw = {
"schema_version": 1,
"connection": {"host": "nas.local"},
}
config = _validate_config(raw)
assert config.connection.host == "nas.local"
assert config.connection.port == 443 # default when https=True
assert config.connection.https is True
assert config.connection.verify_ssl is True
assert config.compose_base_path == "/volume1/docker"
assert config.alias is None
def test_validate_config_full():
raw = {
"schema_version": 1,
"alias": "HomeNAS",
"compose_base_path": "/volume2/containers",
"connection": {
"host": "192.168.1.100",
"port": 5001,
"https": True,
"verify_ssl": False,
},
}
config = _validate_config(raw)
assert config.alias == "HomeNAS"
assert config.compose_base_path == "/volume2/containers"
assert config.connection.host == "192.168.1.100"
assert config.connection.port == 5001
assert config.connection.verify_ssl is False
def test_validate_config_wrong_schema_version():
raw = {
"schema_version": 99,
"connection": {"host": "nas.local"},
}
with pytest.raises(ValueError, match="schema_version"):
_validate_config(raw)
def test_validate_config_missing_host():
raw = {
"schema_version": 1,
"connection": {},
}
with pytest.raises(ValueError, match="connection.host"):
_validate_config(raw)
def test_validate_config_missing_connection():
raw = {"schema_version": 1}
with pytest.raises(ValueError, match="connection.host"):
_validate_config(raw)
def test_merge_env_overrides_host(monkeypatch):
monkeypatch.setenv("SYNOLOGY_HOST", "192.168.1.50")
raw: dict = {"schema_version": 1, "connection": {}}
result = _merge_env_overrides(raw)
assert result["connection"]["host"] == "192.168.1.50"
def test_merge_env_overrides_port(monkeypatch):
monkeypatch.setenv("SYNOLOGY_PORT", "8080")
raw: dict = {"schema_version": 1, "connection": {}}
result = _merge_env_overrides(raw)
assert result["connection"]["port"] == 8080 # coerced to int
def test_merge_env_overrides_https_true(monkeypatch):
monkeypatch.setenv("SYNOLOGY_HTTPS", "true")
raw: dict = {"schema_version": 1, "connection": {}}
result = _merge_env_overrides(raw)
assert result["connection"]["https"] is True
def test_merge_env_overrides_https_false(monkeypatch):
monkeypatch.setenv("SYNOLOGY_HTTPS", "false")
raw: dict = {"schema_version": 1, "connection": {}}
result = _merge_env_overrides(raw)
assert result["connection"]["https"] is False
def test_base_url_https():
config = AppConfig(
schema_version=1,
connection=ConnectionConfig(host="nas.local", port=443, https=True, verify_ssl=True),
)
assert config.base_url == "https://nas.local:443"
def test_base_url_http():
config = AppConfig(
schema_version=1,
connection=ConnectionConfig(host="192.168.1.1", port=5000, https=False, verify_ssl=True),
)
assert config.base_url == "http://192.168.1.1:5000"
def test_keyring_service():
config = AppConfig(
schema_version=1,
connection=ConnectionConfig(host="mynas.local", port=443, https=True, verify_ssl=True),
)
assert config.keyring_service == "mcp-synology-container/mynas.local"
def test_load_config_file_not_found():
with pytest.raises(FileNotFoundError):
load_config("/nonexistent/path/config.yaml")
def test_save_and_load_config(tmp_path):
config = AppConfig(
schema_version=1,
connection=ConnectionConfig(
host="test.nas.local",
port=5001,
https=True,
verify_ssl=False,
),
compose_base_path="/data/docker",
alias="TestNAS",
)
config_file = tmp_path / "config.yaml"
save_config(config, config_file)
assert config_file.exists()
loaded = load_config(config_file)
assert loaded.connection.host == "test.nas.local"
assert loaded.connection.port == 5001
assert loaded.connection.https is True
assert loaded.connection.verify_ssl is False
assert loaded.compose_base_path == "/data/docker"
assert loaded.alias == "TestNAS"
def test_save_config_no_alias(tmp_path):
config = AppConfig(
schema_version=1,
connection=ConnectionConfig(host="nas.local", port=443, https=True, verify_ssl=True),
)
config_file = tmp_path / "config.yaml"
save_config(config, config_file)
raw = yaml.safe_load(config_file.read_text())
assert "alias" not in raw