"""Teste US-002 (PRD 3.3): SessionMiddleware + helper-e sesiune in app/web/session.py.""" from __future__ import annotations import os import tempfile import pytest from fastapi import FastAPI, Request from fastapi.responses import JSONResponse from starlette.middleware.sessions import SessionMiddleware from starlette.testclient import TestClient # ---- App minimal pentru teste (fara init_db, fara DB) ---- def _make_app(web_auth_required: bool = True, session_secret: str = "test-secret-dev") -> FastAPI: """Construieste un app FastAPI minimal cu SessionMiddleware + rute de test.""" mini = FastAPI() mini.add_middleware( SessionMiddleware, secret_key=session_secret, session_cookie="autopass_session", https_only=False, same_site="strict", ) @mini.get("/set-session") def set_sess(request: Request, account_id: int = 1, user_id: int = 1): from app.web.session import set_session set_session(request, account_id, user_id) return {"ok": True} @mini.get("/get-session") def get_sess(request: Request): from app.web.session import current_account, current_user_id return { "account_id": current_account(request), "user_id": current_user_id(request), } @mini.get("/protected") def protected(request: Request): from app.web.session import require_login aid = require_login(request) return {"account_id": aid} @mini.get("/logout") def logout_ep(request: Request): from app.web.session import clear_session clear_session(request) return {"ok": True} @mini.get("/web-account") def web_account_ep(request: Request): from app.web.session import web_account return {"account_id": web_account(request)} # Handler pentru LoginRequired from app.web.session import LoginRequired from starlette.responses import RedirectResponse @mini.exception_handler(LoginRequired) async def login_required_handler(request: Request, exc: LoginRequired): return RedirectResponse("/login", status_code=303) return mini @pytest.fixture() def client_auth(monkeypatch): """Client cu web_auth_required=True.""" monkeypatch.setenv("AUTOPASS_WEB_AUTH_REQUIRED", "true") from app.config import get_settings get_settings.cache_clear() app = _make_app(web_auth_required=True) with TestClient(app, follow_redirects=False) as c: yield c get_settings.cache_clear() @pytest.fixture() def client_dev(monkeypatch): """Client cu web_auth_required=False (dev bypass).""" monkeypatch.setenv("AUTOPASS_WEB_AUTH_REQUIRED", "false") from app.config import get_settings get_settings.cache_clear() app = _make_app(web_auth_required=False) with TestClient(app, follow_redirects=False) as c: yield c get_settings.cache_clear() def test_ruta_protejata_redirect_login(client_auth): """Fara sesiune si web_auth_required=True -> 303 redirect catre /login.""" resp = client_auth.get("/protected") assert resp.status_code == 303 assert resp.headers["location"] == "/login" def test_sesiune_seteaza_si_citeste_cont(client_auth): """set_session stocheaza account_id si user_id; current_account/current_user_id le citesc.""" client_auth.get("/set-session?account_id=5&user_id=7") resp = client_auth.get("/get-session") assert resp.status_code == 200 data = resp.json() assert data["account_id"] == 5 assert data["user_id"] == 7 def test_logout_curata_sesiunea(client_auth): """clear_session sterge account_id si user_id din sesiune.""" client_auth.get("/set-session?account_id=3&user_id=4") # Verifica ca sesiunea e setata data_before = client_auth.get("/get-session").json() assert data_before["account_id"] == 3 # Logout client_auth.get("/logout") data_after = client_auth.get("/get-session").json() assert data_after["account_id"] is None assert data_after["user_id"] is None def test_dev_bypass_cont_1(client_dev, monkeypatch): """web_auth_required=False -> web_account() returneaza 1 (DEFAULT_ACCOUNT_ID) fara sesiune.""" resp = client_dev.get("/web-account") assert resp.status_code == 200 assert resp.json()["account_id"] == 1 def test_set_session_curata_sesiunea_anterioara(client_auth): """set_session face clear() inainte de a seta (C3 anti-fixare sesiune).""" # Seteaza sesiune initiala cu cont 10 client_auth.get("/set-session?account_id=10&user_id=10") data_initial = client_auth.get("/get-session").json() assert data_initial["account_id"] == 10 # Re-login cu cont nou 20 — sesiunea veche trebuie stearsa inainte client_auth.get("/set-session?account_id=20&user_id=20") data_nou = client_auth.get("/get-session").json() assert data_nou["account_id"] == 20 assert data_nou["user_id"] == 20 def test_ruta_protejata_cu_sesiune_trece(client_auth): """Cu sesiune setata si web_auth_required=True -> ruta protejata raspunde 200.""" client_auth.get("/set-session?account_id=5&user_id=5") resp = client_auth.get("/protected") assert resp.status_code == 200 assert resp.json()["account_id"] == 5 def test_web_auth_required_default_true(monkeypatch): """Default-ul de productie: auth web e ON daca AUTOPASS_WEB_AUTH_REQUIRED nu e setat. Dev rapid pe cont 1 = opt-out explicit (AUTOPASS_WEB_AUTH_REQUIRED=false). """ monkeypatch.delenv("AUTOPASS_WEB_AUTH_REQUIRED", raising=False) from app.config import Settings, get_settings get_settings.cache_clear() assert Settings().web_auth_required is True get_settings.cache_clear()