mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-29 03:56:43 +08:00
fix(modules): 默认服务配置改为尊重显式标记,不再按读取顺序取第一个 (#6431)
This commit is contained in:
+11
-2
@@ -202,9 +202,18 @@ class ServiceBase(Generic[TService, TConf], metaclass=ABCMeta):
|
||||
"""
|
||||
获取默认服务配置的名称
|
||||
|
||||
:return: 默认第一个配置的名称
|
||||
优先返回被显式标记为默认的配置。只有在没有任何配置带标记时,才退回到第一个配置——
|
||||
配置的先后来自读取顺序,用户既看不见也控制不了,删掉一个配置会让「默认」静默改指
|
||||
另一个,因此它只能作为无标记时的兜底,不能盖过用户的显式选择。
|
||||
|
||||
:return: 默认配置的名称,无配置时为 None
|
||||
"""
|
||||
# 默认使用第一个配置的名称
|
||||
marked = next(
|
||||
(conf for conf in self._configs.values() if getattr(conf, "default", False)),
|
||||
None,
|
||||
)
|
||||
if marked:
|
||||
return marked.name
|
||||
first_conf = next(iter(self._configs.values()), None)
|
||||
return first_conf.name if first_conf else None
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
"""默认服务配置的选取必须尊重用户的显式标记。
|
||||
|
||||
配置的先后来自读取顺序,用户既看不见也控制不了。按顺序取第一个意味着:删掉一个无关配置,
|
||||
「默认下载器」就会静默改指另一个,而下载任务的归属记录已经按旧的默认写进了历史。
|
||||
"""
|
||||
|
||||
from typing import Dict, Optional
|
||||
|
||||
import pytest
|
||||
|
||||
from app.modules import ServiceBase
|
||||
from app.schemas.system import DownloaderConf
|
||||
|
||||
|
||||
class _StubService(ServiceBase[object, DownloaderConf]):
|
||||
"""只提供配置字典的服务基类桩,不连接任何真实后端。"""
|
||||
|
||||
def __init__(self, configs: Dict[str, DownloaderConf]) -> None:
|
||||
"""记录待测配置,跳过真实服务实例化。
|
||||
|
||||
:param configs: 名称到配置的映射,顺序即读取顺序
|
||||
"""
|
||||
self._configs = configs
|
||||
self._instances = {}
|
||||
self._service_name = "qbittorrent"
|
||||
|
||||
def get_configs(self) -> Dict[str, DownloaderConf]:
|
||||
"""返回构造时传入的配置字典。
|
||||
|
||||
:return: 名称到配置的映射
|
||||
"""
|
||||
return self._configs
|
||||
|
||||
|
||||
def _conf(name: str, *, default: bool = False) -> DownloaderConf:
|
||||
"""构造一份已启用的下载器配置。
|
||||
|
||||
:param name: 配置名称
|
||||
:param default: 是否标记为默认
|
||||
:return: 下载器配置
|
||||
"""
|
||||
return DownloaderConf(
|
||||
name=name,
|
||||
type="qbittorrent",
|
||||
enabled=True,
|
||||
default=default,
|
||||
config={},
|
||||
)
|
||||
|
||||
|
||||
def test_no_config_has_no_default() -> None:
|
||||
"""没有任何配置时不应凭空给出默认名称。"""
|
||||
service = _StubService({})
|
||||
|
||||
assert service.get_default_config_name() is None
|
||||
|
||||
|
||||
def test_single_config_is_the_default() -> None:
|
||||
"""只有一份配置时它就是默认,无需用户额外标记。"""
|
||||
service = _StubService({"only": _conf("only")})
|
||||
|
||||
assert service.get_default_config_name() == "only"
|
||||
|
||||
|
||||
def test_marked_config_wins_over_order() -> None:
|
||||
"""标记为默认的配置优先,即使它不排在最前。"""
|
||||
service = _StubService(
|
||||
{
|
||||
"first": _conf("first"),
|
||||
"second": _conf("second", default=True),
|
||||
}
|
||||
)
|
||||
|
||||
assert service.get_default_config_name() == "second"
|
||||
|
||||
|
||||
def test_marked_config_survives_reordering() -> None:
|
||||
"""读取顺序变化不得改变已标记的默认配置。
|
||||
|
||||
这是本修复要守住的性质:顺序是实现细节,标记才是用户的意思。
|
||||
"""
|
||||
marked = _conf("marked", default=True)
|
||||
plain = _conf("plain")
|
||||
|
||||
forward = _StubService({"marked": marked, "plain": plain})
|
||||
backward = _StubService({"plain": plain, "marked": marked})
|
||||
|
||||
assert forward.get_default_config_name() == "marked"
|
||||
assert backward.get_default_config_name() == "marked"
|
||||
|
||||
|
||||
def test_unmarked_configs_fall_back_to_first() -> None:
|
||||
"""一个标记都没有时保持原有行为,不改变既有部署的默认目标。"""
|
||||
service = _StubService(
|
||||
{
|
||||
"alpha": _conf("alpha"),
|
||||
"beta": _conf("beta"),
|
||||
}
|
||||
)
|
||||
|
||||
assert service.get_default_config_name() == "alpha"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("name", ["alpha", "beta"])
|
||||
def test_get_config_without_name_follows_the_default(name: str) -> None:
|
||||
"""不指定名称时取到的必须是默认配置本身。"""
|
||||
service = _StubService(
|
||||
{
|
||||
"alpha": _conf("alpha", default=name == "alpha"),
|
||||
"beta": _conf("beta", default=name == "beta"),
|
||||
}
|
||||
)
|
||||
|
||||
resolved: Optional[DownloaderConf] = service.get_config()
|
||||
|
||||
assert resolved is not None
|
||||
assert resolved.name == name
|
||||
Reference in New Issue
Block a user