单任务受控执行(15 态状态机 + 审计轨迹)、DAG 管道、Controller 门面。
执行器三个:线程(默认,含 async def 任务)、内联(同步 / 测试)、进程
(spawn 子进程:硬性停止、绕开 GIL、崩溃隔离)。
调度:并发额度 + 每桶限流 + 具名资源信号量(按标签)+ 优先级排队。
持久层:TaskStore 契约 + 内存 / SQLite / Postgres 实现,契约测试随包发布。
跨进程与多节点:写穿 / 读穿、指令通道与租约、owned_buckets 划界、reconcile。
CLI、12 个可直接运行的示例、docs/ 下 5 份文档。
门禁:ruff / ruff format / mypy(strict) 干净;
pytest 563 passed(44 skipped 是需要真实 Postgres 的那批);
带一台可连的 Postgres 时 607 passed。
84 lines
2.9 KiB
Python
84 lines
2.9 KiB
Python
"""公开 API 的表面测试。
|
||
|
||
``chongming_task`` 的 ``__init__`` 是**嵌入其他应用**的入口,因此它本身的正确性
|
||
值得一条用例:漏导出某个名字、或者导出顺序导致循环导入,都会让集成方第一步就失败。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import chongming_task
|
||
|
||
|
||
def test_version_is_exposed() -> None:
|
||
assert chongming_task.__version__
|
||
|
||
|
||
def test_all_has_no_duplicates() -> None:
|
||
"""重复导出会让"到底哪个生效"变得不确定。
|
||
|
||
顺序**不在这里**断言:``__all__`` 的排序由 ruff 的 ``RUF022``(isort 风格,
|
||
全大写常量优先)负责,那是 lint 的职责。写一条与 linter 规则不一致的断言,
|
||
只会让两边互相打架。
|
||
"""
|
||
names = chongming_task.__all__
|
||
assert len(names) == len(set(names))
|
||
|
||
|
||
def test_every_exported_name_resolves() -> None:
|
||
"""``__all__`` 里写了却取不到,等于给集成方埋了一个 ImportError。"""
|
||
missing = [name for name in chongming_task.__all__ if not hasattr(chongming_task, name)]
|
||
assert missing == []
|
||
|
||
|
||
def test_primary_integration_surface_is_importable() -> None:
|
||
"""这一段就是 README 里"嵌入你自己的应用"的最小示例。"""
|
||
from chongming_task import ( # noqa: F401 - 只为验证可导入
|
||
Controller,
|
||
InMemoryTaskStore,
|
||
SqliteTaskStore,
|
||
TaskStatus,
|
||
TaskStore,
|
||
run_task,
|
||
)
|
||
|
||
controller = Controller(max_parallel=2)
|
||
assert controller.registry.names() == ()
|
||
assert TaskStatus.PENDING.value == "pending"
|
||
assert callable(run_task)
|
||
|
||
|
||
def test_store_implementations_satisfy_the_protocol() -> None:
|
||
"""存储实现必须满足契约——第三方后端也照这条自证。"""
|
||
from chongming_task import InMemoryTaskStore, SqliteTaskStore, TaskStore
|
||
|
||
assert isinstance(InMemoryTaskStore(), TaskStore)
|
||
|
||
store = SqliteTaskStore(":memory:")
|
||
try:
|
||
assert isinstance(store, TaskStore)
|
||
finally:
|
||
# 不关掉连接会在解释器退出时触发 ResourceWarning;本项目的 pytest 配置
|
||
# 把 warning 升级为 error,因此泄漏是会被抓住的。
|
||
store.close()
|
||
|
||
|
||
def test_controller_accepts_a_store() -> None:
|
||
"""存储已经接线。
|
||
|
||
这条用例原先钉的是"尚未接线"——当 ``Controller(store=...)`` 真的开始工作时,
|
||
它会自己失败并提示删掉。现在它钉的是接线本身。
|
||
"""
|
||
from chongming_task import Controller, InMemoryTaskStore
|
||
|
||
store = InMemoryTaskStore()
|
||
controller = Controller(store=store, max_parallel=2)
|
||
assert controller.store is store
|
||
assert controller.persist_failures == ()
|
||
assert controller.owner
|
||
|
||
|
||
def test_private_helpers_are_not_exported() -> None:
|
||
"""以下划线开头的实现细节不应出现在公开表面上。"""
|
||
leaked = [name for name in chongming_task.__all__ if name.startswith("_")]
|
||
assert leaked == []
|