"""Teste US-001: endpoint-uri de integrare (GET /v1/ping + export Postman). TDD — toate testele RED inainte de implementare. """ from __future__ import annotations import json import os import tempfile import pytest from fastapi.testclient import TestClient # --------------------------------------------------------------------------- # # Fixture client izolat # # --------------------------------------------------------------------------- # @pytest.fixture() def client(monkeypatch): """Client FastAPI cu DB temporara izolata, require_api_key=False (dev).""" tmp = tempfile.mkdtemp() monkeypatch.setenv("AUTOPASS_DB_PATH", os.path.join(tmp, "t.db")) monkeypatch.setenv("AUTOPASS_REQUIRE_API_KEY", "false") monkeypatch.setenv("AUTOPASS_RAR_ENV", "test") from app.config import get_settings get_settings.cache_clear() from app.main import app with TestClient(app) as c: yield c get_settings.cache_clear() @pytest.fixture() def client_prod(monkeypatch): """Client cu require_api_key=True (mod prod).""" tmp = tempfile.mkdtemp() monkeypatch.setenv("AUTOPASS_DB_PATH", os.path.join(tmp, "t.db")) monkeypatch.setenv("AUTOPASS_REQUIRE_API_KEY", "true") monkeypatch.setenv("AUTOPASS_RAR_ENV", "prod") from app.config import get_settings get_settings.cache_clear() from app.main import app with TestClient(app) as c: yield c get_settings.cache_clear() def _creeaza_cheie(monkeypatch) -> str: """Seed cont id=1 + creeaza cheie API; intoarce cheia in clar.""" from app.db import get_connection from app.auth import create_api_key conn = get_connection() try: cheie = create_api_key(conn, 1) conn.commit() finally: conn.close() return cheie def _seteaza_rar_creds(monkeypatch=None) -> None: """Seteaza rar_creds_enc pe contul id=1.""" from app.db import get_connection from app.crypto import encrypt_creds conn = get_connection() try: enc = encrypt_creds({"email": "test@rar.ro", "password": "secret"}) conn.execute("UPDATE accounts SET rar_creds_enc=? WHERE id=1", (enc,)) conn.commit() finally: conn.close() # --------------------------------------------------------------------------- # # Teste ping # # --------------------------------------------------------------------------- # def test_ping_cu_cheie_valida_200(client, monkeypatch): """GET /v1/ping cu X-API-Key valida -> 200 cu campurile cerute.""" cheie = _creeaza_cheie(monkeypatch) r = client.get("/v1/ping", headers={"X-API-Key": cheie}) assert r.status_code == 200, r.text body = r.json() assert "account_id" in body assert "mediu" in body assert "autentificat_cu_cheie" in body assert "are_creds_rar" in body assert "ts" in body assert body["autentificat_cu_cheie"] is True assert body["mediu"] == "test" def test_ping_cu_bearer_valid_200(client, monkeypatch): """GET /v1/ping cu Authorization: Bearer valida -> 200, autentificat_cu_cheie=True.""" cheie = _creeaza_cheie(monkeypatch) r = client.get("/v1/ping", headers={"Authorization": f"Bearer {cheie}"}) assert r.status_code == 200, r.text body = r.json() assert body["autentificat_cu_cheie"] is True assert body["account_id"] == 1 def test_ping_fara_cheie_dev_cont_implicit(client, monkeypatch): """Fara cheie, require_api_key=False -> cont 1, autentificat_cu_cheie=False.""" r = client.get("/v1/ping") assert r.status_code == 200, r.text body = r.json() assert body["account_id"] == 1 assert body["autentificat_cu_cheie"] is False def test_ping_x_api_key_gol_in_dev_cont_implicit(client, monkeypatch): """X-API-Key cu doar spatii = lipsa cheie -> cont 1, autentificat_cu_cheie=False in dev.""" r = client.get("/v1/ping", headers={"X-API-Key": " "}) assert r.status_code == 200, r.text body = r.json() assert body["account_id"] == 1 assert body["autentificat_cu_cheie"] is False def test_ping_are_creds_rar_reflecta_contul(client, monkeypatch): """Cont fara creds -> are_creds_rar=False; dupa setare -> True.""" # Fara creds r1 = client.get("/v1/ping") assert r1.status_code == 200 assert r1.json()["are_creds_rar"] is False # Seteaza creds pe cont 1 _seteaza_rar_creds() r2 = client.get("/v1/ping") assert r2.status_code == 200 assert r2.json()["are_creds_rar"] is True def test_ping_cheie_invalida_401(client, monkeypatch): """Cheie invalida -> 401, indiferent de require_api_key.""" r = client.get("/v1/ping", headers={"X-API-Key": "rfak_cheie_falsa_xxxxxxxx"}) assert r.status_code == 401 def test_ping_prod_fara_cheie_401(client_prod, monkeypatch): """require_api_key=True, fara cheie -> 401.""" r = client_prod.get("/v1/ping") assert r.status_code == 401 def test_ruta_ping_inregistrata_o_singura_data(client, monkeypatch): """Ruta /v1/ping trebuie sa apara exact o data in app.routes.""" from app.main import app rute_ping = [r for r in app.routes if hasattr(r, "path") and r.path == "/v1/ping"] assert len(rute_ping) == 1, f"Asteptat 1 ruta /v1/ping, gasit: {len(rute_ping)}" # --------------------------------------------------------------------------- # # Teste export Postman # # --------------------------------------------------------------------------- # def test_postman_export_json_valid(client, monkeypatch): """GET /v1/integrare/postman.json -> 200, Content-Type JSON, structura Postman v2.1.0.""" r = client.get("/v1/integrare/postman.json") assert r.status_code == 200, r.text assert "application/json" in r.headers.get("content-type", "") body = r.json() assert "info" in body assert "v2.1.0" in body["info"].get("schema", ""), f"Schema gresita: {body['info'].get('schema')}" def test_postman_contine_exact_trei_requesturi(client, monkeypatch): """Colectia Postman trebuie sa contina exact 3 requesturi cu headers si url corecte.""" r = client.get("/v1/integrare/postman.json") assert r.status_code == 200 body = r.json() items = body.get("item", []) assert len(items) == 3, f"Asteptat 3 requesturi, gasit: {len(items)}" for item in items: req = item.get("request", {}) # Fiecare trebuie sa aiba header X-API-Key cu valoarea {{api_key}} headers = req.get("header", []) cheie_header = [h for h in headers if h.get("key") == "X-API-Key"] assert len(cheie_header) == 1, f"Header X-API-Key lipsa in request '{item.get('name')}'" assert cheie_header[0].get("value") == "{{api_key}}", \ f"Valoare header gresita: {cheie_header[0].get('value')}" # URL-ul trebuie sa contina {{base_url}} url = req.get("url", {}) url_raw = url.get("raw", "") if isinstance(url, dict) else str(url) assert "{{base_url}}" in url_raw, \ f"{{{{base_url}}}} lipsa in url pentru '{item.get('name')}': {url_raw}" def test_postman_nu_deriva_din_app_routes(client, monkeypatch): """Colectia Postman contine EXACT cele 3 rute allowlist, nu mai mult.""" r = client.get("/v1/integrare/postman.json") assert r.status_code == 200 body = r.json() items = body.get("item", []) # Extrage URL-urile / path-urile din colectie cai_expuse = set() for item in items: req = item.get("request", {}) url = req.get("url", {}) url_raw = url.get("raw", "") if isinstance(url, dict) else str(url) # Normalizeaza: scoate {{base_url}} si parametrii query cale = url_raw.replace("{{base_url}}", "").split("?")[0] cai_expuse.add(cale) # Allowlist: exact acestea 3 allowlist = {"/v1/prezentari", "/v1/import", "/v1/ping"} assert cai_expuse == allowlist, \ f"Colectia expune cai neasteptate: {cai_expuse - allowlist} sau lipsesc: {allowlist - cai_expuse}"