refactor: expand runtime contracts and debt ratchets

This commit is contained in:
jxxghp
2026-08-22 08:25:36 +08:00
parent 820f7e8850
commit 5d9c6c8b19
37 changed files with 883 additions and 339 deletions
+40 -12
View File
@@ -1,28 +1,60 @@
"""数据库备份与宿主调度器的接入合同。"""
import ast
from dataclasses import replace
from pathlib import Path
from unittest.mock import Mock
from app import scheduler as scheduler_module
from app.scheduler import Scheduler
from app.application.configuration import SchedulerRuntimeConfig
class _SchedulerStub:
"""记录 Scheduler 注册结果的最小调度器替身。"""
def __init__(self) -> None:
"""初始化空作业表。"""
self.jobs = {}
def add_job(self, func, *, trigger, id, **kwargs) -> None:
"""按作业 ID 保存最近一次注册参数。"""
self.jobs[id] = {"func": func, "trigger": trigger, **kwargs}
def _scheduler() -> Scheduler:
"""构造不启动后台线程的 Scheduler。"""
scheduler = object.__new__(Scheduler)
scheduler._scheduler = _SchedulerStub()
scheduler._jobs = {}
return scheduler
def _config(**changes) -> SchedulerRuntimeConfig:
"""构造数据库备份测试所需的最小调度配置快照。"""
config = SchedulerRuntimeConfig(
dev=False,
timezone="Asia/Shanghai",
scheduler_workers=1,
db_backup_enable=False,
db_backup_cron="",
cookiecloud_interval=None,
mediaserver_sync_interval=None,
subscribe_search=False,
subscribe_search_interval=24,
subscribe_mode="rss",
subscribe_rss_interval=30,
data_cleanup_enable=False,
sitedata_refresh_interval=None,
memory_gc_interval=None,
ai_agent_enable=False,
ai_agent_job_interval=None,
usage_statistic_share=False,
site_link=None,
)
return replace(config, **changes)
def test_database_backup_schedule_only_watches_job_shape() -> None:
assert Scheduler.CONFIG_WATCH.intersection({
"DB_BACKUP_ENABLE",
@@ -34,22 +66,19 @@ def test_database_backup_schedule_only_watches_job_shape() -> None:
}) == {"DB_BACKUP_ENABLE", "DB_BACKUP_CRON"}
def test_disabled_database_backup_does_not_register_job(monkeypatch) -> None:
def test_disabled_database_backup_does_not_register_job() -> None:
"""关闭备份时不注册作业。"""
scheduler = _scheduler()
monkeypatch.setattr(scheduler_module.settings, "DB_BACKUP_ENABLE", False)
scheduler._register_database_backup_job()
scheduler._register_database_backup_job(_config())
assert scheduler._scheduler.jobs == {}
def test_enabled_database_backup_without_cron_does_not_register_job(monkeypatch) -> None:
def test_enabled_database_backup_without_cron_does_not_register_job() -> None:
"""总开关开启但未配置周期时,不启用定时备份。"""
scheduler = _scheduler()
monkeypatch.setattr(scheduler_module.settings, "DB_BACKUP_ENABLE", True)
monkeypatch.setattr(scheduler_module.settings, "DB_BACKUP_CRON", "")
scheduler._register_database_backup_job()
scheduler._register_database_backup_job(_config(db_backup_enable=True))
assert scheduler._scheduler.jobs == {}
@@ -57,12 +86,11 @@ def test_enabled_database_backup_without_cron_does_not_register_job(monkeypatch)
def test_enabled_database_backup_registers_single_replaceable_job(monkeypatch) -> None:
scheduler = _scheduler()
trigger = object()
monkeypatch.setattr(scheduler_module.settings, "DB_BACKUP_ENABLE", True)
monkeypatch.setattr(scheduler_module.settings, "DB_BACKUP_CRON", "0 3 * * *")
monkeypatch.setattr(scheduler_module.TimerUtils, "build_schedule_trigger", Mock(return_value=trigger))
config = _config(db_backup_enable=True, db_backup_cron="0 3 * * *")
scheduler._register_database_backup_job()
scheduler._register_database_backup_job()
scheduler._register_database_backup_job(config)
scheduler._register_database_backup_job(config)
assert list(scheduler._scheduler.jobs) == ["database_backup"]
assert scheduler._scheduler.jobs["database_backup"]["replace_existing"] is True