"""OTA 检查更新端点测试。 覆盖:公开读端点未配置时返回默认(latest_version_code=0=无更新)、内部写端点鉴权 (503 未配 / 401 头错 / 200)、写后能读到同一组值、写入参数校验(422)。 """ from __future__ import annotations import pytest from fastapi.testclient import TestClient from app.core.config import settings from app.db.session import SessionLocal from app.models.app_config import AppConfig from app.repositories.app_config import APP_VERSION_KEY _SECRET = "test-internal-secret-only-for-pytest" # 合法 body(够过 pydantic 校验,用于鉴权用例) _VALID = { "latest_version_code": 31, "latest_version_name": "0.1.6", "apk_url": "https://app-api.shaguabijia.com/media/releases/shaguabijia-v0.1.6-build31.apk", } @pytest.fixture() def clean_version(): """每个用例前后清掉 latest_app_version 行(表由 conftest 建好,session 级共享)。""" def _clear(): s = SessionLocal() s.query(AppConfig).filter(AppConfig.key == APP_VERSION_KEY).delete() s.commit() s.close() _clear() yield _clear() def test_read_default_when_unset(client: TestClient, clean_version) -> None: """未配置任何版本时,公开读端点返回 latest_version_code=0(客户端视为已是最新);不鉴权。""" r = client.get("/api/v1/platform/app-version") assert r.status_code == 200, r.text assert r.json()["latest_version_code"] == 0 def test_write_secret_unset_503(client: TestClient, clean_version, monkeypatch) -> None: monkeypatch.setattr(settings, "INTERNAL_API_SECRET", "") # 未配 = 写端点关闭 r = client.post("/internal/app-version", json=_VALID) assert r.status_code == 503 def test_write_auth(client: TestClient, clean_version, monkeypatch) -> None: monkeypatch.setattr(settings, "INTERNAL_API_SECRET", _SECRET) assert client.post("/internal/app-version", json=_VALID).status_code == 401 assert client.post( "/internal/app-version", json=_VALID, headers={"X-Internal-Secret": "wrong"} ).status_code == 401 r = client.post("/internal/app-version", json=_VALID, headers={"X-Internal-Secret": _SECRET}) assert r.status_code == 200, r.text def test_write_then_read(client: TestClient, clean_version, monkeypatch) -> None: monkeypatch.setattr(settings, "INTERNAL_API_SECRET", _SECRET) payload = { "latest_version_code": 99, "latest_version_name": "9.9.9", "apk_url": "https://app-api.shaguabijia.com/media/releases/shaguabijia-v9.9.9-build99.apk", "update_note": "测试更新说明", "min_supported_version_code": 50, "apk_size_bytes": 12345678, "apk_sha256": "abc123", } w = client.post("/internal/app-version", json=payload, headers={"X-Internal-Secret": _SECRET}) assert w.status_code == 200, w.text assert w.json()["latest_version_code"] == 99 body = client.get("/api/v1/platform/app-version").json() assert body["latest_version_code"] == 99 assert body["latest_version_name"] == "9.9.9" assert body["apk_url"] == payload["apk_url"] assert body["update_note"] == "测试更新说明" assert body["min_supported_version_code"] == 50 assert body["apk_size_bytes"] == 12345678 assert body["apk_sha256"] == "abc123" def test_write_rejects_invalid(client: TestClient, clean_version, monkeypatch) -> None: monkeypatch.setattr(settings, "INTERNAL_API_SECRET", _SECRET) h = {"X-Internal-Secret": _SECRET} # latest_version_code 必须 > 0 bad_code = {"latest_version_code": 0, "latest_version_name": "x", "apk_url": "u"} assert client.post("/internal/app-version", json=bad_code, headers=h).status_code == 422 # apk_url 不能空 bad_url = {"latest_version_code": 5, "latest_version_name": "x", "apk_url": ""} assert client.post("/internal/app-version", json=bad_url, headers=h).status_code == 422