US-007: rute web proprii /cont/roteste-cheie + /cont/rar-creds scoped pe sesiune (C13), sectiune "Contul meu" cu cheie afisata o data. US-010: rol admin (users.is_admin) + require_admin->403 + CLI set-admin + bootstrap primul cont=admin (count_admins in BEGIN IMMEDIATE, anti-race). US-011: panou /admin (activare/dezactivare conturi, CSRF + PRG), link admin + logout pe dashboard. US-012: app/email.py notify_signup best-effort degradat fara SMTP + config smtp_*. Fix: migrare defensiva users.is_admin/email_verified in _migrate. VERIFY x2 context curat (PASS) + /code-review high. 393 teste pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
125 lines
4.6 KiB
Python
125 lines
4.6 KiB
Python
"""Teste migrare defensiva coloane users (is_admin, email_verified).
|
|
|
|
TDD: RED -> implementare in _migrate -> GREEN.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sqlite3
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from app.db import _migrate, init_db, get_connection
|
|
from app.config import get_settings
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Test 1: _migrate adauga is_admin si email_verified pe o tabela users minima
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def test_migrate_adauga_is_admin_pe_users_veche() -> None:
|
|
"""Pe un DB cu tabela users creata fara is_admin/email_verified,
|
|
_migrate trebuie sa adauge ambele coloane."""
|
|
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as f:
|
|
db_path = Path(f.name)
|
|
|
|
conn = sqlite3.connect(str(db_path), isolation_level=None)
|
|
conn.row_factory = sqlite3.Row
|
|
conn.execute("PRAGMA journal_mode = WAL")
|
|
conn.execute("PRAGMA foreign_keys = OFF") # evitam FK checks pe schema minima
|
|
|
|
# Tabela accounts minima (necesara pentru FK la users).
|
|
# Trebuie sa aiba cui + rar_creds_enc + active ca _migrate sa nu crape
|
|
# pe ALTER/CREATE INDEX care le refera inainte de blocul users.
|
|
conn.execute("""
|
|
CREATE TABLE accounts (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL,
|
|
cui TEXT,
|
|
active INTEGER NOT NULL DEFAULT 1,
|
|
rar_creds_enc TEXT
|
|
)
|
|
""")
|
|
conn.execute("INSERT INTO accounts (id, name) VALUES (1, 'default')")
|
|
|
|
# Tabela submissions minima (necesara pentru _migrate -- coloane submissions)
|
|
conn.execute("""
|
|
CREATE TABLE submissions (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
idempotency_key TEXT NOT NULL UNIQUE,
|
|
account_id INTEGER,
|
|
status TEXT NOT NULL DEFAULT 'queued',
|
|
payload_json TEXT NOT NULL,
|
|
rar_creds_enc TEXT,
|
|
rar_status_code INTEGER,
|
|
rar_error TEXT,
|
|
id_prezentare INTEGER,
|
|
retry_count INTEGER NOT NULL DEFAULT 0,
|
|
next_attempt_at TEXT,
|
|
sending_since TEXT,
|
|
purge_after TEXT,
|
|
batch_id INTEGER,
|
|
row_index INTEGER,
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
)
|
|
""")
|
|
|
|
# Tabela users MINIMA: fara is_admin, fara email_verified
|
|
conn.execute("""
|
|
CREATE TABLE users (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
account_id INTEGER NOT NULL,
|
|
email TEXT NOT NULL UNIQUE,
|
|
password_hash TEXT NOT NULL,
|
|
salt TEXT NOT NULL,
|
|
scrypt_params TEXT NOT NULL,
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
)
|
|
""")
|
|
|
|
try:
|
|
# Rulam migrarea
|
|
_migrate(conn)
|
|
|
|
# Verificam ca ambele coloane au fost adaugate
|
|
cols = {r["name"] for r in conn.execute("PRAGMA table_info(users)").fetchall()}
|
|
assert "is_admin" in cols, f"is_admin lipseste dupa migrare; coloane prezente: {cols}"
|
|
assert "email_verified" in cols, f"email_verified lipseste dupa migrare; coloane prezente: {cols}"
|
|
finally:
|
|
conn.close()
|
|
db_path.unlink(missing_ok=True)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Test 2: _migrate este idempotent pe un DB initializat normal cu init_db()
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def test_migrate_idempotent_pe_users_curenta(tmp_path: pytest.TempPathFactory, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
"""Pe un DB initializat normal, re-apelarea _migrate nu ridica exceptie
|
|
si coloanele is_admin/email_verified raman prezente."""
|
|
db_file = tmp_path / "test_idem.db"
|
|
monkeypatch.setenv("AUTOPASS_DB_PATH", str(db_file))
|
|
|
|
# Resetam settings-ul cached ca sa preia noul AUTOPASS_DB_PATH
|
|
get_settings.cache_clear() # type: ignore[attr-defined]
|
|
|
|
try:
|
|
# Initializare normala
|
|
init_db()
|
|
|
|
# Re-apelam _migrate direct (idempotenta)
|
|
conn = get_connection()
|
|
try:
|
|
_migrate(conn) # nu trebuie sa ridice
|
|
|
|
cols = {r["name"] for r in conn.execute("PRAGMA table_info(users)").fetchall()}
|
|
assert "is_admin" in cols
|
|
assert "email_verified" in cols
|
|
finally:
|
|
conn.close()
|
|
finally:
|
|
get_settings.cache_clear() # type: ignore[attr-defined]
|