Files
kite/backend/tests/test_settings.py
T
curo1305 21ec9cb4c3 test(03-01): add Wave 0 xfail stubs and shared fixtures for Phase 3
- Add auth_user, admin_user, mock_minio_presigned, mock_minio_stat fixtures to conftest.py
- Create test_quota.py with 4 xfail stubs (STORE-03, STORE-05, STORE-06, SC2 race)
- Append test_migration_0003 to test_alembic.py (full pre-seed + post-migration assertions)
- Append 3 classifier xfail stubs (DOC-03, DOC-05, D-15)
- Append 6 document xfail stubs (D-05, STORE-04, SEC-04, D-16)
- Append 4 topic xfail stubs (DOC-04, D-09, D-17)
- Append test_settings_endpoint_removed stub (D-12)
- All 19 new test IDs collect cleanly with xfail(strict=False)
2026-05-23 13:42:37 +02:00

124 lines
4.7 KiB
Python

"""
Settings API tests — async only (Plan 05 cutover).
Settings remain flat-file backed in Phase 1 (D-03 deferred), so these tests
use async_client but do not require a real database session.
"""
from __future__ import annotations
import pytest
async def test_get_settings_defaults(async_client, tmp_path, monkeypatch):
# Point SETTINGS_FILE at a temp dir so tests don't clobber each other
import config as cfg
monkeypatch.setattr(cfg, "SETTINGS_FILE", tmp_path / "settings.json")
import services.storage as st
monkeypatch.setattr(st, "SETTINGS_FILE", tmp_path / "settings.json")
resp = await async_client.get("/api/settings")
assert resp.status_code == 200
data = resp.json()
assert data["active_provider"] == "lmstudio"
assert "system_prompt" in data
assert "providers" in data
async def test_patch_system_prompt(async_client, tmp_path, monkeypatch):
import config as cfg
monkeypatch.setattr(cfg, "SETTINGS_FILE", tmp_path / "settings.json")
import services.storage as st
monkeypatch.setattr(st, "SETTINGS_FILE", tmp_path / "settings.json")
new_prompt = "Custom system prompt for testing."
resp = await async_client.patch("/api/settings", json={"system_prompt": new_prompt})
assert resp.status_code == 200
resp2 = await async_client.get("/api/settings")
assert resp2.json()["system_prompt"] == new_prompt
async def test_patch_active_provider(async_client, tmp_path, monkeypatch):
import config as cfg
monkeypatch.setattr(cfg, "SETTINGS_FILE", tmp_path / "settings.json")
import services.storage as st
monkeypatch.setattr(st, "SETTINGS_FILE", tmp_path / "settings.json")
resp = await async_client.patch("/api/settings", json={"active_provider": "ollama"})
assert resp.status_code == 200
assert resp.json()["active_provider"] == "ollama"
async def test_patch_invalid_provider(async_client, tmp_path, monkeypatch):
import config as cfg
monkeypatch.setattr(cfg, "SETTINGS_FILE", tmp_path / "settings.json")
import services.storage as st
monkeypatch.setattr(st, "SETTINGS_FILE", tmp_path / "settings.json")
resp = await async_client.patch("/api/settings", json={"active_provider": "unknown"})
assert resp.status_code == 400
async def test_patch_provider_config(async_client, tmp_path, monkeypatch):
import config as cfg
monkeypatch.setattr(cfg, "SETTINGS_FILE", tmp_path / "settings.json")
import services.storage as st
monkeypatch.setattr(st, "SETTINGS_FILE", tmp_path / "settings.json")
resp = await async_client.patch(
"/api/settings",
json={
"providers": {
"ollama": {"model": "mistral", "base_url": "http://host.docker.internal:11434"}
}
},
)
assert resp.status_code == 200
assert resp.json()["providers"]["ollama"]["model"] == "mistral"
async def test_masked_api_key_not_overwritten(async_client, tmp_path, monkeypatch):
"""Patching with a masked key should not overwrite the real stored key."""
import config as cfg
monkeypatch.setattr(cfg, "SETTINGS_FILE", tmp_path / "settings.json")
import services.storage as st
monkeypatch.setattr(st, "SETTINGS_FILE", tmp_path / "settings.json")
# First set a real key
await async_client.patch(
"/api/settings",
json={"providers": {"anthropic": {"api_key": "sk-ant-realkey"}}},
)
# Then patch with masked key (simulating frontend re-submitting)
await async_client.patch(
"/api/settings",
json={"providers": {"anthropic": {"api_key": "****key"}}},
)
# The stored key should still be the real one
stored = st.load_settings()
assert stored["providers"]["anthropic"]["api_key"] == "sk-ant-realkey"
async def test_get_default_prompt(async_client):
resp = await async_client.get("/api/settings/default-prompt")
assert resp.status_code == 200
assert "system_prompt" in resp.json()
assert len(resp.json()["system_prompt"]) > 0
# ---------------------------------------------------------------------------
# Wave 0 xfail stub — D-12: /api/settings endpoint removed in Plan 03-04
# ---------------------------------------------------------------------------
@pytest.mark.xfail(strict=False, reason="implemented in plan 03-04")
async def test_settings_endpoint_removed(async_client):
"""GET /api/settings returns 404 after the flat-file settings system is retired.
D-12: the /api/settings endpoint is removed entirely in Phase 3. All AI config
comes from the database (users.ai_provider / users.ai_model set by admin).
The flat-file services/storage.py load_settings()/save_settings() functions
are also deleted (CONTEXT.md D-12).
"""
assert True # scaffold