feat: FASE 7 - Polish & Testing (security, i18n, test suite, docs)
Security hardening: CORS lockdown, rate limiting middleware con sliding window e eviction IP stale, security headers (CSP, HSTS, X-Frame-Options), session cookie hardening, filename sanitization upload. i18n completion: internazionalizzati barcode.js e csv-export.js con bridge window.BARCODE_I18N/CSV_I18N, aggiornati .po IT/EN con 27 nuove stringhe. Tablet UX: touch target 44px per dispositivi coarse pointer. Test suite: 101 test totali (76 server + 25 client), copertura completa di tutti i router API, autenticazione, ruoli, CRUD, SPC, file upload, security integration. Infrastruttura SQLite async in-memory con fixtures. Fix critici: MissingGreenlet in recipe_service (selectinload eager), route ordering tasks.py, auth_service bcrypt diretto, Measurement.id Integer per SQLite. Documentazione: API.md (riferimento completo 40+ endpoint), DEPLOYMENT.md (guida produzione con Docker/Nginx/SSL), USER_GUIDE.md (manuale utente per ruolo). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
"""Tests for settings router (/api/settings)."""
|
||||
import pytest
|
||||
from httpx import AsyncClient
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from models.setting import SystemSetting
|
||||
from models.user import User
|
||||
from tests.conftest import auth_headers
|
||||
|
||||
|
||||
class TestGetSettings:
|
||||
"""GET /api/settings/ tests."""
|
||||
|
||||
async def test_get_settings(
|
||||
self,
|
||||
client: AsyncClient,
|
||||
admin_user: User,
|
||||
db_session: AsyncSession,
|
||||
):
|
||||
"""Authenticated user can retrieve settings."""
|
||||
# Seed a setting
|
||||
setting = SystemSetting(
|
||||
setting_key="test_setting",
|
||||
setting_value="test_value",
|
||||
setting_type="string",
|
||||
)
|
||||
db_session.add(setting)
|
||||
await db_session.flush()
|
||||
|
||||
resp = await client.get(
|
||||
"/api/settings/", headers=auth_headers(admin_user)
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert isinstance(data, dict)
|
||||
assert data.get("test_setting") == "test_value"
|
||||
|
||||
async def test_get_settings_empty(
|
||||
self, client: AsyncClient, maker_user: User
|
||||
):
|
||||
"""Empty settings returns empty dict."""
|
||||
resp = await client.get(
|
||||
"/api/settings/", headers=auth_headers(maker_user)
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
assert resp.json() == {} or isinstance(resp.json(), dict)
|
||||
|
||||
async def test_get_setting_by_key(
|
||||
self,
|
||||
client: AsyncClient,
|
||||
admin_user: User,
|
||||
db_session: AsyncSession,
|
||||
):
|
||||
"""Settings dict contains specific key after creation."""
|
||||
setting = SystemSetting(
|
||||
setting_key="csv_delimiter",
|
||||
setting_value=";",
|
||||
setting_type="string",
|
||||
)
|
||||
db_session.add(setting)
|
||||
await db_session.flush()
|
||||
|
||||
resp = await client.get(
|
||||
"/api/settings/", headers=auth_headers(admin_user)
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["csv_delimiter"] == ";"
|
||||
|
||||
|
||||
class TestUpdateSettings:
|
||||
"""PUT /api/settings/ tests."""
|
||||
|
||||
async def test_update_settings(
|
||||
self, client: AsyncClient, admin_user: User
|
||||
):
|
||||
"""Admin can update/create settings."""
|
||||
resp = await client.put(
|
||||
"/api/settings/",
|
||||
headers=auth_headers(admin_user),
|
||||
json={
|
||||
"company_name": "Tielogic Srl",
|
||||
"csv_delimiter": ",",
|
||||
},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["message"].startswith("Updated")
|
||||
assert "company_name" in data["updated_keys"]
|
||||
assert "csv_delimiter" in data["updated_keys"]
|
||||
|
||||
# Verify persistence
|
||||
get_resp = await client.get(
|
||||
"/api/settings/", headers=auth_headers(admin_user)
|
||||
)
|
||||
settings = get_resp.json()
|
||||
assert settings["company_name"] == "Tielogic Srl"
|
||||
|
||||
async def test_settings_require_admin(
|
||||
self, client: AsyncClient, maker_user: User
|
||||
):
|
||||
"""Non-admin user cannot update settings."""
|
||||
resp = await client.put(
|
||||
"/api/settings/",
|
||||
headers=auth_headers(maker_user),
|
||||
json={"some_key": "some_value"},
|
||||
)
|
||||
assert resp.status_code == 403
|
||||
Reference in New Issue
Block a user