Files
MoviePilot/tests/test_network_composition.py

149 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""网络应用端口组合根契约测试。"""
from types import SimpleNamespace
from unittest.mock import AsyncMock, MagicMock
import pytest
from app.startup.composition import network as network_composition
@pytest.mark.asyncio
async def test_network_test_transport_enforces_safe_http_options(monkeypatch) -> None:
"""网络探测适配器固定证书校验、超时和手动重定向策略。"""
captured = {}
response = SimpleNamespace(status_code=200, headers={}, text="ok")
class _RequestUtils:
"""捕获网络探测适配器使用的 HTTP 参数。"""
def __init__(self, **kwargs) -> None:
"""记录通用请求工具的构造参数。"""
captured["options"] = kwargs
async def get_res(self, url, allow_redirects=True):
"""记录请求地址和重定向开关并返回固定响应。"""
captured["url"] = url
captured["allow_redirects"] = allow_redirects
return response
monkeypatch.setattr(network_composition, "AsyncRequestUtils", _RequestUtils)
result = await network_composition._NetworkTestTransportAdapter().get(
"https://example.com/health",
proxy="http://proxy.example:7890",
headers={"Authorization": "Bearer test"},
user_agent="MoviePilot-Test",
)
assert result is response
assert captured == {
"url": "https://example.com/health",
"allow_redirects": False,
"options": {
"proxies": "http://proxy.example:7890",
"headers": {"Authorization": "Bearer test"},
"timeout": 10,
"ua": "MoviePilot-Test",
"verify": True,
"follow_redirects": False,
},
}
def test_image_transport_forwards_sync_request_options(monkeypatch) -> None:
"""同步图片适配器完整透传请求参数,并单独传递目标 URL。"""
response = object()
request = MagicMock()
request.get_res.return_value = response
request_factory = MagicMock(return_value=request)
monkeypatch.setattr(network_composition, "RequestUtils", request_factory)
options = {
"timeout": 15,
"proxies": "http://proxy.example:7890",
"headers": {"Accept": "image/*"},
}
result = network_composition._ImageTransportAdapter().get(
"https://images.example/poster.jpg",
options=options,
)
assert result is response
request_factory.assert_called_once_with(**options)
request.get_res.assert_called_once_with(
url="https://images.example/poster.jpg",
)
@pytest.mark.asyncio
async def test_image_transport_forwards_async_request_options(monkeypatch) -> None:
"""异步图片适配器完整透传请求参数,并单独传递目标 URL。"""
response = object()
request = MagicMock()
request.get_res = AsyncMock(return_value=response)
request_factory = MagicMock(return_value=request)
monkeypatch.setattr(network_composition, "AsyncRequestUtils", request_factory)
options = {
"timeout": 20,
"proxies": None,
"verify": True,
}
result = await network_composition._ImageTransportAdapter().async_get(
"https://images.example/backdrop.webp",
options=options,
)
assert result is response
request_factory.assert_called_once_with(**options)
request.get_res.assert_awaited_once_with(
url="https://images.example/backdrop.webp",
)
def test_internal_address_adapter_delegates_to_ip_utility(monkeypatch) -> None:
"""内部地址判断必须原样委托通用 IP 工具。"""
probe = MagicMock(return_value=True)
monkeypatch.setattr(network_composition.IpUtils, "is_internal", probe)
assert network_composition._InternalAddressAdapter().is_internal("http://192.168.1.10/image.jpg") is True
probe.assert_called_once_with("http://192.168.1.10/image.jpg")
def test_network_port_composition_does_not_read_settings_early(monkeypatch) -> None:
"""端口装配只登记延迟 reader不得在配置发布前读取 RuntimeSettings。"""
get_runtime_settings = MagicMock(side_effect=AssertionError("装配阶段不得读取 RuntimeSettings"))
configured = {}
monkeypatch.setattr(
network_composition,
"get_runtime_settings",
get_runtime_settings,
)
monkeypatch.setattr(
network_composition,
"configure_network_test_service",
lambda service: configured.update(network=service),
)
monkeypatch.setattr(
network_composition,
"configure_image_ports",
lambda **ports: configured.update(image=ports),
)
monkeypatch.setattr(
network_composition,
"configure_message_ingress_port",
lambda port: configured.update(message=port),
)
network_composition.configure_application_network_ports()
get_runtime_settings.assert_not_called()
assert set(configured) == {"network", "image", "message"}
runtime_settings = MagicMock()
runtime_settings.get.return_value = "configured"
get_runtime_settings.side_effect = None
get_runtime_settings.return_value = runtime_settings
assert configured["network"]._settings("PROXY", None) == "configured"
runtime_settings.get.assert_called_once_with("PROXY", None)