mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/jxxghp/MoviePilot.git
synced 2026-09-20 08:03:34 +08:00
149 lines
5.2 KiB
Python
149 lines
5.2 KiB
Python
"""网络应用端口组合根契约测试。"""
|
||
|
||
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)
|