2026-09-30 12:34:19 +08:00
|
|
|
|
"""B0 冒烟:工具链与包结构可用(不测业务逻辑,业务逻辑随 B1 迁移进来)。"""
|
2026-09-30 12:32:52 +08:00
|
|
|
|
|
2026-09-30 12:34:19 +08:00
|
|
|
|
import ast
|
2026-09-30 12:32:52 +08:00
|
|
|
|
import subprocess
|
|
|
|
|
|
import sys
|
2026-09-30 12:34:19 +08:00
|
|
|
|
from pathlib import Path
|
2026-09-30 12:32:52 +08:00
|
|
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
2026-09-30 12:34:19 +08:00
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
SRC = ROOT / "src" / "aps"
|
|
|
|
|
|
|
|
|
|
|
|
# 平台侧模块名与旧仓库里 APS 代码的模块名:出现即视为跨系统依赖(ADR-0010 边界规则)
|
|
|
|
|
|
PLATFORM_MODULES = {"server", "agent_core", "aps_domain", "aps_engines", "aps_state", "aps_importers"}
|
|
|
|
|
|
|
2026-09-30 12:32:52 +08:00
|
|
|
|
|
|
|
|
|
|
def test_package_imports() -> None:
|
|
|
|
|
|
import aps
|
|
|
|
|
|
|
|
|
|
|
|
assert aps.__version__ == "0.1.0"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("name", ["api", "domain", "engines", "state", "importers", "governance"])
|
|
|
|
|
|
def test_subpackages_import(name: str) -> None:
|
|
|
|
|
|
"""每个子包都对应 B 线的一个搬迁目标,导入不了说明结构被改坏了。"""
|
|
|
|
|
|
module = __import__(f"aps.{name}", fromlist=[name])
|
|
|
|
|
|
|
|
|
|
|
|
assert module.__doc__, f"aps.{name} 缺少说明它负责什么的 docstring"
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-09-30 12:34:19 +08:00
|
|
|
|
def test_no_platform_module_imports() -> None:
|
|
|
|
|
|
"""边界规则(ADR-0010):APS 不得 import 平台代码,只允许走 HTTP 契约。
|
|
|
|
|
|
|
|
|
|
|
|
B3 会用 CI 卡住这条;这里先把它变成可执行规则,任何新增文件一旦越界立刻红。
|
|
|
|
|
|
"""
|
|
|
|
|
|
offenders: list[str] = []
|
|
|
|
|
|
for path in sorted(SRC.rglob("*.py")):
|
|
|
|
|
|
tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(path))
|
|
|
|
|
|
for node in ast.walk(tree):
|
|
|
|
|
|
if isinstance(node, ast.Import):
|
|
|
|
|
|
names = [alias.name for alias in node.names]
|
|
|
|
|
|
elif isinstance(node, ast.ImportFrom):
|
|
|
|
|
|
names = [node.module or ""]
|
|
|
|
|
|
else:
|
|
|
|
|
|
continue
|
|
|
|
|
|
for name in names:
|
|
|
|
|
|
if name.split(".")[0] in PLATFORM_MODULES:
|
|
|
|
|
|
offenders.append(f"{path.relative_to(ROOT)}: {name}")
|
|
|
|
|
|
|
|
|
|
|
|
assert offenders == [], "APS 不得依赖平台代码:" + ";".join(offenders)
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-09-30 12:32:52 +08:00
|
|
|
|
def test_platform_code_is_not_imported() -> None:
|
|
|
|
|
|
"""APS 不依赖平台代码:aps 包内不得出现对平台模块的引用(ADR-0010)。"""
|
|
|
|
|
|
result = subprocess.run(
|
|
|
|
|
|
[
|
|
|
|
|
|
sys.executable,
|
|
|
|
|
|
"-c",
|
|
|
|
|
|
"import aps, aps.api, aps.domain, aps.engines, aps.state, aps.importers, aps.governance",
|
|
|
|
|
|
],
|
|
|
|
|
|
capture_output=True,
|
|
|
|
|
|
text=True,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
assert result.returncode == 0, result.stderr
|