Files
shaguabijia-app-server/tests/test_ensure_pg.py
T
guke 3f449d3600 fix(dev): ensure_pg 智能定位 Docker Desktop(装 D 盘等非默认盘符也能自动拉起)
原先把 Docker Desktop.exe 写死在 %ProgramFiles%\Docker\Docker\,装在 D 盘就自动拉起
失败(明明 docker CLI 已在 PATH 上可用、只是 daemon 没启)。改为按可靠性排序的多路探测:
DOCKER_DESKTOP_EXE 显式指定 → 从 PATH 上 docker CLI 反推安装目录(跟随实际盘符)→
注册表 → 各 Program Files 变体兜底;找不到时提示 DOCKER_DESKTOP_EXE / sqlite 逃生舱。
.env.example 记一笔用法。

顺带修一个先前就红、与现行"sqlite→降级返 True"契约矛盾的测试
(test_ensure_rejects_sqlite → test_ensure_sqlite_escape_hatch)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-28 14:13:11 +08:00

130 lines
4.1 KiB
Python

"""scripts/ensure_pg.py 纯函数单测(不需要 Docker/PG)。"""
from __future__ import annotations
import socket
from scripts.ensure_pg import (
_docker_desktop_cmd,
_docker_desktop_from_registry,
_is_sqlite,
_parse_host_port,
_port_open,
_win_docker_desktop_candidates,
ensure,
)
def test_is_sqlite():
assert _is_sqlite("sqlite:///./data/app.db")
assert _is_sqlite(" SQLite:///x ")
assert not _is_sqlite("postgresql+psycopg://u:p@localhost:5432/db")
def test_parse_host_port_full():
assert _parse_host_port(
"postgresql+psycopg://u:p@localhost:5432/shaguabijia"
) == ("localhost", 5432)
def test_parse_host_port_defaults():
# 缺端口 → 5432
assert _parse_host_port("postgresql+psycopg://u:p@db.example/x")[1] == 5432
# 缺 host → localhost
assert _parse_host_port("postgresql+psycopg:///x") == ("localhost", 5432)
def test_parse_host_port_testdb():
assert _parse_host_port(
"postgresql+psycopg://u:p@localhost:5432/shaguabijia_test"
) == ("localhost", 5432)
def test_port_open_true():
srv = socket.socket()
srv.bind(("127.0.0.1", 0))
srv.listen(1)
port = srv.getsockname()[1]
try:
assert _port_open("127.0.0.1", port, timeout=1.0)
finally:
srv.close()
def test_port_open_false():
s = socket.socket()
s.bind(("127.0.0.1", 0))
port = s.getsockname()[1]
s.close() # 释放端口,无人监听 → 连接应失败
assert not _port_open("127.0.0.1", port, timeout=0.3)
def test_win_candidates_override_wins():
env = {
"DOCKER_DESKTOP_EXE": r"X:\custom\Docker Desktop.exe",
"ProgramFiles": r"C:\Program Files",
}
cands = [str(p) for p in _win_docker_desktop_candidates(env, None)]
assert cands[0] == r"X:\custom\Docker Desktop.exe"
def test_win_candidates_follow_cli_drive():
# 核心:docker CLI 在 D 盘 → 反推出 D 盘的 Docker Desktop.exe(不再写死 C 盘)
env = {"ProgramFiles": r"C:\Program Files"}
cli = r"D:\Docker\Docker\resources\bin\docker.exe"
cands = [str(p) for p in _win_docker_desktop_candidates(env, cli)]
assert r"D:\Docker\Docker\Docker Desktop.exe" in cands
# 兜底的 C 盘常见路径也仍在
assert r"C:\Program Files\Docker\Docker\Docker Desktop.exe" in cands
def test_win_candidates_no_cli_uses_program_files():
env = {"ProgramFiles": r"C:\Program Files"}
cands = [str(p) for p in _win_docker_desktop_candidates(env, None)]
assert cands == [r"C:\Program Files\Docker\Docker\Docker Desktop.exe"]
def test_docker_desktop_cmd_windows_found(monkeypatch, tmp_path):
exe = tmp_path / "Docker Desktop.exe"
exe.write_text("") # 真实存在
monkeypatch.setattr("scripts.ensure_pg._find_docker_desktop_exe", lambda: exe)
assert _docker_desktop_cmd("win32") == [str(exe)]
def test_docker_desktop_cmd_windows_not_found(monkeypatch):
monkeypatch.setattr("scripts.ensure_pg._find_docker_desktop_exe", lambda: None)
assert _docker_desktop_cmd("win32") is None
def test_docker_desktop_cmd_darwin():
assert _docker_desktop_cmd("darwin") == ["open", "-a", "Docker"]
def test_docker_desktop_cmd_linux():
assert _docker_desktop_cmd("linux") is None
def test_registry_probe_never_raises():
# best-effort:无论平台/有无键,只返回 Path 或 None,绝不抛
r = _docker_desktop_from_registry()
assert r is None or hasattr(r, "exists")
def test_ensure_sqlite_escape_hatch(monkeypatch):
# sqlite 是【显式降级逃生舱】:打印横幅、返回 True,且绝不触碰 docker
def _boom():
raise AssertionError("sqlite 分支不应调用 docker")
monkeypatch.setattr("scripts.ensure_pg._docker_cli_ok", _boom)
assert ensure("sqlite:///./data/app.db") is True
def test_ensure_shortcircuits_when_pg_up(monkeypatch):
# 端口通 → 直接 True,绝不触碰 docker
monkeypatch.setattr("scripts.ensure_pg._port_open", lambda *a, **k: True)
def _boom():
raise AssertionError("端口通时不应调用 docker")
monkeypatch.setattr("scripts.ensure_pg._docker_cli_ok", _boom)
assert ensure("postgresql+psycopg://u:p@localhost:5432/shaguabijia") is True