Files
MusicServer/tests/test_serve.py
T
snowy-yang 0cae770ace feat(server): 支持 Granian 与 rloop/uvloop/winloop 事件循环
- 新增 scripts/serve.py 启动器:server auto/uvicorn/granian,循环可用性与平台校验(显式不可用直接报错)
- pyproject 增加 granian 可选 extra(granian[reload,rloop,uvloop,winloop],平台 marker 由 granian 维护)
- tests/test_serve.py 覆盖服务器/循环选择与命令拼装;README 补充启动方式、循环矩阵与多 worker 限制
2026-10-23 22:12:08 +08:00

68 lines
2.7 KiB
Python

"""启动器(scripts/serve.py)的循环/服务器选择逻辑测试(不启动真实服务器)。"""
from __future__ import annotations
import sys
from pathlib import Path
import pytest
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from scripts import serve
def test_pick_server_auto_prefers_granian(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(serve, "has_module", lambda name: name == "granian")
assert serve.pick_server("auto") == "granian"
monkeypatch.setattr(serve, "has_module", lambda name: False)
assert serve.pick_server("auto") == "uvicorn"
def test_available_loops_follow_installed_packages(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(serve, "has_module", lambda name: name == "winloop")
assert serve.available_loops("granian") == ["auto", "asyncio", "winloop"]
assert serve.available_loops("uvicorn") == ["auto", "asyncio"]
monkeypatch.setattr(serve, "has_module", lambda name: name in ("rloop", "uvloop"))
assert serve.available_loops("granian") == ["auto", "asyncio", "rloop", "uvloop"]
assert serve.available_loops("uvicorn") == ["auto", "asyncio", "uvloop"]
def test_explicit_unavailable_loop_fails_with_hint(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(serve, "has_module", lambda name: False)
with pytest.raises(SystemExit) as error:
serve.resolve_loop("granian", "rloop")
message = str(error.value)
assert "rloop" in message and "可用" in message
def test_uvicorn_rejects_granian_only_loops() -> None:
with pytest.raises(SystemExit):
serve.resolve_loop("uvicorn", "winloop")
with pytest.raises(SystemExit):
serve.resolve_loop("uvicorn", "rloop")
def test_uvicorn_auto_and_asyncio_allowed() -> None:
assert serve.resolve_loop("uvicorn", "auto") == "auto"
assert serve.resolve_loop("uvicorn", "asyncio") == "asyncio"
def test_build_command_granian(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(serve, "has_module", lambda name: True)
command = serve.build_command("granian", host="0.0.0.0", port=16688, workers=2, loop="winloop", reload=True)
assert command[:3] == [sys.executable, "-m", "granian"]
assert command[command.index("--loop") + 1] == "winloop"
assert command[command.index("--workers") + 1] == "2"
assert "--reload" in command
assert command[-1] == serve.APP_TARGET
def test_build_command_uvicorn() -> None:
command = serve.build_command("uvicorn", host="127.0.0.1", port=9000, workers=1, loop="auto", reload=False)
assert command[:3] == [sys.executable, "-m", "uvicorn"]
assert command[3] == serve.APP_TARGET
assert "--reload" not in command