158 lines
6.1 KiB
Python
158 lines
6.1 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from pathlib import Path
|
|
|
|
from fastapi.testclient import TestClient
|
|
|
|
from app.core.security import create_jwt
|
|
from app.db.models.base import Base
|
|
from app.main import create_app
|
|
|
|
|
|
def test_admin_put_settings_updates_and_get_reflects(tmp_path: Path, monkeypatch) -> None:
|
|
db_path = tmp_path / "admin_put_settings.db"
|
|
db_url = "sqlite+aiosqlite:///" + db_path.as_posix()
|
|
|
|
monkeypatch.setenv("APP_ENV", "dev")
|
|
monkeypatch.setenv("DATABASE_URL", db_url)
|
|
monkeypatch.setenv("SECRET_KEY", "secret_test")
|
|
monkeypatch.setenv("ADMIN_USERNAME", "admin")
|
|
|
|
app = create_app()
|
|
|
|
async def _migrate() -> None:
|
|
async with app.state.engine.begin() as conn:
|
|
await conn.run_sync(Base.metadata.create_all)
|
|
|
|
asyncio.run(_migrate())
|
|
|
|
token = create_jwt(secret_key="secret_test", subject="admin", ttl_s=3600)
|
|
with TestClient(app) as client:
|
|
put_resp = client.put(
|
|
"/admin/api/settings",
|
|
headers={"Authorization": f"Bearer {token}", "X-Request-Id": "req_test"},
|
|
json={
|
|
"settings": {
|
|
"proxy": {
|
|
"enabled": True,
|
|
"fail_closed": False,
|
|
"route_mode": "allowlist",
|
|
"allowlist_domains": ["i.pximg.net"],
|
|
},
|
|
"random": {
|
|
"default_attempts": 5,
|
|
"default_r18_strict": False,
|
|
"fail_cooldown_ms": 12345,
|
|
"strategy": "random",
|
|
"quality_samples": 7,
|
|
"recommendation": {
|
|
"pick_mode": "best",
|
|
"temperature": 2.5,
|
|
"score_weights": {"bookmark": 10, "view": 1},
|
|
"multipliers": {"ai": 0.5, "manga": 0},
|
|
},
|
|
},
|
|
"security": {"hide_origin_url_in_public_json": False},
|
|
"rate_limit": {"proxy_probe_concurrency": 7},
|
|
}
|
|
},
|
|
)
|
|
assert put_resp.status_code == 200
|
|
body1 = put_resp.json()
|
|
assert body1["ok"] is True
|
|
assert body1["updated"] >= 4
|
|
assert body1["request_id"] == "req_test"
|
|
assert put_resp.headers["X-Request-Id"] == "req_test"
|
|
|
|
get_resp = client.get(
|
|
"/admin/api/settings",
|
|
headers={"Authorization": f"Bearer {token}", "X-Request-Id": "req_test"},
|
|
)
|
|
assert get_resp.status_code == 200
|
|
body2 = get_resp.json()
|
|
assert body2["ok"] is True
|
|
|
|
settings = body2["settings"]
|
|
assert settings["proxy"]["enabled"] is True
|
|
assert settings["proxy"]["fail_closed"] is False
|
|
assert settings["proxy"]["route_mode"] == "allowlist"
|
|
assert settings["proxy"]["allowlist_domains"] == ["i.pximg.net"]
|
|
|
|
assert settings["random"]["default_attempts"] == 5
|
|
assert settings["random"]["default_r18_strict"] is False
|
|
assert settings["random"]["fail_cooldown_ms"] == 12345
|
|
assert settings["random"]["strategy"] == "random"
|
|
assert settings["random"]["quality_samples"] == 7
|
|
assert settings["random"]["recommendation"]["pick_mode"] == "best"
|
|
assert settings["random"]["recommendation"]["temperature"] == 2.5
|
|
assert settings["random"]["recommendation"]["score_weights"]["bookmark"] == 10.0
|
|
assert settings["random"]["recommendation"]["score_weights"]["view"] == 1.0
|
|
assert settings["random"]["recommendation"]["multipliers"]["ai"] == 0.5
|
|
assert settings["random"]["recommendation"]["multipliers"]["manga"] == 0.0
|
|
|
|
assert settings["security"]["hide_origin_url_in_public_json"] is False
|
|
assert settings["rate_limit"]["proxy_probe_concurrency"] == 7
|
|
|
|
|
|
def test_admin_put_settings_rejects_invalid_route_mode(tmp_path: Path, monkeypatch) -> None:
|
|
db_path = tmp_path / "admin_put_settings_bad_route_mode.db"
|
|
db_url = "sqlite+aiosqlite:///" + db_path.as_posix()
|
|
|
|
monkeypatch.setenv("APP_ENV", "dev")
|
|
monkeypatch.setenv("DATABASE_URL", db_url)
|
|
monkeypatch.setenv("SECRET_KEY", "secret_test")
|
|
monkeypatch.setenv("ADMIN_USERNAME", "admin")
|
|
|
|
app = create_app()
|
|
|
|
async def _migrate() -> None:
|
|
async with app.state.engine.begin() as conn:
|
|
await conn.run_sync(Base.metadata.create_all)
|
|
|
|
asyncio.run(_migrate())
|
|
|
|
token = create_jwt(secret_key="secret_test", subject="admin", ttl_s=3600)
|
|
with TestClient(app) as client:
|
|
resp = client.put(
|
|
"/admin/api/settings",
|
|
headers={"Authorization": f"Bearer {token}", "X-Request-Id": "req_test"},
|
|
json={"settings": {"proxy": {"route_mode": "nope"}}},
|
|
)
|
|
assert resp.status_code == 400
|
|
body = resp.json()
|
|
assert body["ok"] is False
|
|
assert body["code"] == "BAD_REQUEST"
|
|
assert body["request_id"] == "req_test"
|
|
|
|
|
|
def test_admin_put_settings_rejects_invalid_random_recommendation(tmp_path: Path, monkeypatch) -> None:
|
|
db_path = tmp_path / "admin_put_settings_bad_recommendation.db"
|
|
db_url = "sqlite+aiosqlite:///" + db_path.as_posix()
|
|
|
|
monkeypatch.setenv("APP_ENV", "dev")
|
|
monkeypatch.setenv("DATABASE_URL", db_url)
|
|
monkeypatch.setenv("SECRET_KEY", "secret_test")
|
|
monkeypatch.setenv("ADMIN_USERNAME", "admin")
|
|
|
|
app = create_app()
|
|
|
|
async def _migrate() -> None:
|
|
async with app.state.engine.begin() as conn:
|
|
await conn.run_sync(Base.metadata.create_all)
|
|
|
|
asyncio.run(_migrate())
|
|
|
|
token = create_jwt(secret_key="secret_test", subject="admin", ttl_s=3600)
|
|
with TestClient(app) as client:
|
|
resp = client.put(
|
|
"/admin/api/settings",
|
|
headers={"Authorization": f"Bearer {token}", "X-Request-Id": "req_test"},
|
|
json={"settings": {"random": {"recommendation": {"pick_mode": "nope"}}}},
|
|
)
|
|
assert resp.status_code == 400
|
|
body = resp.json()
|
|
assert body["ok"] is False
|
|
assert body["code"] == "BAD_REQUEST"
|
|
assert body["request_id"] == "req_test"
|