mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-03 06:27:27 +08:00
refactor: unify plugin release pagination
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
"""插件 Release 同步与异步分页策略一致性测试。"""
|
||||
|
||||
import pytest
|
||||
|
||||
from app.adapters.external.market import PluginHelper
|
||||
|
||||
|
||||
class _PageResponse:
|
||||
"""提供同步与异步分页入口共同消费的最小响应合同。"""
|
||||
|
||||
def __init__(self, payload, status_code: int = 200) -> None:
|
||||
"""保存待返回的 JSON 数据和 HTTP 状态。"""
|
||||
self._payload = payload
|
||||
self.status_code = status_code
|
||||
|
||||
def json(self):
|
||||
"""返回当前页预置的 JSON 数据。"""
|
||||
if isinstance(self._payload, Exception):
|
||||
raise self._payload
|
||||
return self._payload
|
||||
|
||||
|
||||
def _release_payload(size: int, *, offset: int = 0) -> list[dict]:
|
||||
"""生成可区分页次的 GitHub Release 最小响应。"""
|
||||
return [
|
||||
{
|
||||
"tag_name": f"DemoPlugin_v1.0.{offset + index}",
|
||||
"assets": [
|
||||
{"name": f"demoplugin_v1.0.{offset + index}.zip"},
|
||||
],
|
||||
}
|
||||
for index in range(size)
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sync_and_async_release_pages_share_policy(monkeypatch) -> None:
|
||||
"""同步与异步分页必须请求相同页并产生相同规范化仓库快照。"""
|
||||
helper = PluginHelper()
|
||||
repo_url = "https://github.com/policy-owner/release-repository"
|
||||
responses = [
|
||||
_PageResponse(_release_payload(100)),
|
||||
_PageResponse(_release_payload(1, offset=100)),
|
||||
]
|
||||
sync_requests: list[tuple[str, dict]] = []
|
||||
async_requests: list[tuple[str, dict]] = []
|
||||
|
||||
def sync_request(url: str, **kwargs):
|
||||
"""记录同步分页请求并按页返回响应。"""
|
||||
sync_requests.append((url, kwargs))
|
||||
return responses[len(sync_requests) - 1]
|
||||
|
||||
async def async_request(url: str, **kwargs):
|
||||
"""记录异步分页请求并采用相同响应序列。"""
|
||||
async_requests.append((url, kwargs))
|
||||
return responses[len(async_requests) - 1]
|
||||
|
||||
monkeypatch.setattr(
|
||||
helper,
|
||||
"_PluginHelper__request_with_fallback",
|
||||
sync_request,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
helper,
|
||||
"_PluginHelper__async_request_with_fallback",
|
||||
async_request,
|
||||
)
|
||||
|
||||
helper._get_plugin_repo_releases.cache_clear()
|
||||
await helper._async_get_plugin_repo_releases.cache_clear()
|
||||
sync_result = helper._get_plugin_repo_releases(repo_url)
|
||||
# 两个装饰器共享仓库级缓存;清除后再覆盖异步网络入口。
|
||||
await helper._async_get_plugin_repo_releases.cache_clear()
|
||||
async_result = await helper._async_get_plugin_repo_releases(repo_url)
|
||||
|
||||
assert sync_result == async_result
|
||||
assert len(sync_result or []) == 101
|
||||
assert sync_requests == async_requests
|
||||
assert [request[0].rsplit("page=", 1)[1] for request in sync_requests] == [
|
||||
"1",
|
||||
"2",
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("response", "expected", "release_count"),
|
||||
[
|
||||
(None, None, 0),
|
||||
(_PageResponse([], 200), False, 0),
|
||||
(_PageResponse([{"tag_name": "DemoPlugin_v1.0.0"}], 200), False, 1),
|
||||
(_PageResponse(_release_payload(100), 200), True, 100),
|
||||
(_PageResponse({"message": "bad payload"}, 200), None, 0),
|
||||
(_PageResponse([], 503), None, 0),
|
||||
(_PageResponse(ValueError("invalid json"), 200), None, 0),
|
||||
],
|
||||
)
|
||||
def test_release_page_merge_preserves_stop_and_failure_contract(
|
||||
response,
|
||||
expected: bool | None,
|
||||
release_count: int,
|
||||
) -> None:
|
||||
"""统一分页解析必须区分继续、自然结束和整次仓库读取失败。"""
|
||||
releases: list[dict] = []
|
||||
|
||||
result = PluginHelper._merge_plugin_release_page(
|
||||
"https://github.com/policy-owner/release-repository",
|
||||
response,
|
||||
releases,
|
||||
)
|
||||
|
||||
assert result is expected
|
||||
assert len(releases) == release_count
|
||||
Reference in New Issue
Block a user