5fe8f5bc73
- pull_image: SYNO.Docker.Image/pull with repository+tag split via rpartition; polls image list every 3 s until image appears, 120 s timeout - list_registries: SYNO.Docker.Registry/get; shows name, URL, active marker - Gruppe 5 (Volumes) removed from roadmap — SYNO.Docker.Volume does not exist - CLAUDE.md: tool count 17 → 19, Volumes section removed - 28 tests all passing Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
174 lines
5.1 KiB
Python
174 lines
5.1 KiB
Python
"""Tests for modules/registries.py."""
|
|
|
|
from unittest.mock import AsyncMock
|
|
|
|
import pytest
|
|
|
|
|
|
def make_mock_mcp():
|
|
tools: dict = {}
|
|
|
|
class MockMCP:
|
|
def tool(self):
|
|
def decorator(fn):
|
|
tools[fn.__name__] = fn
|
|
return fn
|
|
|
|
return decorator
|
|
|
|
return MockMCP(), tools
|
|
|
|
|
|
def make_config():
|
|
from mcp_synology_container.config import AppConfig, ConnectionConfig
|
|
|
|
return AppConfig(
|
|
schema_version=1,
|
|
connection=ConnectionConfig(host="nas.local", port=443, https=True, verify_ssl=True),
|
|
)
|
|
|
|
|
|
SAMPLE_REGISTRIES = {
|
|
"registries": [
|
|
{
|
|
"name": "Docker Hub",
|
|
"url": "https://registry.hub.docker.com",
|
|
"syno": True,
|
|
"enable_registry_mirror": False,
|
|
"enable_trust_SSC": True,
|
|
"mirror_urls": [],
|
|
},
|
|
{
|
|
"name": "GitHub Packages",
|
|
"url": "https://ghcr.io",
|
|
"syno": False,
|
|
"enable_registry_mirror": False,
|
|
"enable_trust_SSC": True,
|
|
"mirror_urls": [],
|
|
},
|
|
],
|
|
"using": "Docker Hub",
|
|
"total": 2,
|
|
"offset": 0,
|
|
}
|
|
|
|
|
|
# ──────────────────────────────────────────────────────────────────────────────
|
|
# list_registries
|
|
# ──────────────────────────────────────────────────────────────────────────────
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_registries_shows_all():
|
|
from mcp_synology_container.modules.registries import register_registries
|
|
|
|
client = AsyncMock()
|
|
client.request.return_value = SAMPLE_REGISTRIES
|
|
mcp, tools = make_mock_mcp()
|
|
register_registries(mcp, make_config(), client)
|
|
|
|
result = await tools["list_registries"]()
|
|
|
|
assert "Docker Hub" in result
|
|
assert "GitHub Packages" in result
|
|
assert "registry.hub.docker.com" in result
|
|
assert "ghcr.io" in result
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_registries_marks_active():
|
|
from mcp_synology_container.modules.registries import register_registries
|
|
|
|
client = AsyncMock()
|
|
client.request.return_value = SAMPLE_REGISTRIES
|
|
mcp, tools = make_mock_mcp()
|
|
register_registries(mcp, make_config(), client)
|
|
|
|
result = await tools["list_registries"]()
|
|
|
|
# Docker Hub is the active registry
|
|
assert "[active]" in result
|
|
# GitHub Packages is not active — "[active]" appears only once
|
|
assert result.count("[active]") == 1
|
|
|
|
pos_hub = result.index("Docker Hub")
|
|
pos_active = result.index("[active]")
|
|
pos_github = result.index("GitHub Packages")
|
|
# [active] marker appears right after "Docker Hub", before "GitHub Packages"
|
|
assert pos_hub < pos_active < pos_github
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_registries_uses_get_method():
|
|
"""list_registries must call SYNO.Docker.Registry with method='get'."""
|
|
from mcp_synology_container.modules.registries import register_registries
|
|
|
|
client = AsyncMock()
|
|
client.request.return_value = SAMPLE_REGISTRIES
|
|
mcp, tools = make_mock_mcp()
|
|
register_registries(mcp, make_config(), client)
|
|
|
|
await tools["list_registries"]()
|
|
|
|
client.request.assert_called_once()
|
|
call_args = client.request.call_args
|
|
assert call_args.args[0] == "SYNO.Docker.Registry"
|
|
assert call_args.args[1] == "get"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_registries_mirror_flag():
|
|
from mcp_synology_container.modules.registries import register_registries
|
|
|
|
data = {
|
|
"registries": [
|
|
{
|
|
"name": "Mirror Registry",
|
|
"url": "https://mirror.example.com",
|
|
"syno": False,
|
|
"enable_registry_mirror": True,
|
|
"mirror_urls": ["https://mirror.example.com"],
|
|
}
|
|
],
|
|
"using": "",
|
|
}
|
|
|
|
client = AsyncMock()
|
|
client.request.return_value = data
|
|
mcp, tools = make_mock_mcp()
|
|
register_registries(mcp, make_config(), client)
|
|
|
|
result = await tools["list_registries"]()
|
|
|
|
assert "[mirror enabled]" in result
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_registries_empty():
|
|
from mcp_synology_container.modules.registries import register_registries
|
|
|
|
client = AsyncMock()
|
|
client.request.return_value = {"registries": [], "using": ""}
|
|
mcp, tools = make_mock_mcp()
|
|
register_registries(mcp, make_config(), client)
|
|
|
|
result = await tools["list_registries"]()
|
|
|
|
assert "No registries" in result
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_list_registries_api_error():
|
|
from mcp_synology_container.dsm_client import SynologyError
|
|
from mcp_synology_container.modules.registries import register_registries
|
|
|
|
client = AsyncMock()
|
|
client.request.side_effect = SynologyError("Permission denied", code=105)
|
|
mcp, tools = make_mock_mcp()
|
|
register_registries(mcp, make_config(), client)
|
|
|
|
result = await tools["list_registries"]()
|
|
|
|
assert "Error" in result
|
|
assert "Permission denied" in result
|