refactor: comentarii strict functionale, fara referinte PRD/stories
Curatare globala a comentariilor si docstring-urilor (app, tools, teste, scripturi): eliminate referintele la PRD-uri, US-xxx, task-uri istorice si review-uri; pastrata doar informatia functionala, formulata scurt. Regula adaugata in CLAUDE.md (sectiunea Stil). Fara modificari de cod sau comportament. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -22,9 +22,9 @@ os.environ.setdefault("AUTOPASS_WORKER_USE_TEST_CREDS", "false")
|
||||
# lazy-load-eze modelul de ~230MB la fiecare test care atinge editorul de mapari
|
||||
# (suita rapida, fara download in CI). Testele de embeddings il pornesc punctual.
|
||||
os.environ.setdefault("AUTOPASS_EMBEDDINGS_ENABLED", "false")
|
||||
# Seed-ul de operatii etichetate (SILVER, PRD 5.18) e ON in app, dar OFF in teste:
|
||||
# multe teste presupun mapping_suggestions GOL la init_db. Testele US-004/005/006 il
|
||||
# pornesc punctual (object.__setattr__ pe settings sau apel direct la seeder).
|
||||
# Seed-ul de operatii etichetate e ON in app, dar OFF in teste: multe teste presupun
|
||||
# mapping_suggestions GOL la init_db. Testele care au nevoie de el il pornesc punctual
|
||||
# (object.__setattr__ pe settings sau apel direct la seeder).
|
||||
os.environ.setdefault("AUTOPASS_SEED_OPERATII_ENABLED", "false")
|
||||
|
||||
|
||||
@@ -35,15 +35,15 @@ _REAL_INIT_DB = None
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _auto_send_on_default_account(request, monkeypatch):
|
||||
"""PRD 5.19 US-009: contul default id=1 (seed schema.sql, INSERT OR IGNORE) porneste pe
|
||||
"""Contul default id=1 (seed schema.sql, INSERT OR IGNORE) porneste pe
|
||||
`auto_send_enabled=0` (Auto OFF) — corect in productie (nimic nu pleaca fara confirmare).
|
||||
|
||||
Dar suita exercita lantul `POST -> claim_one -> sent` pe contul id=1
|
||||
(test_import_e2e, test_creds_delivery, test_live_rar): cu Auto OFF, ingestia ar marca
|
||||
`held=1` (US-002) si worker-ul (`claim_one ... AND held=0`, US-003) nu ar mai lua randul
|
||||
`held=1` si worker-ul (`claim_one ... AND held=0`) nu ar mai lua randul
|
||||
-> testele ar stagna tacit. E un fix de STARE DB, nu env var (coloana e per-rand in
|
||||
`accounts`), deci il aplicam wraparind `init_db` (contul id=1 NU e creat de `create_account`
|
||||
-> un patch pe factory NU l-ar acoperi — Eng HIGH).
|
||||
-> un patch pe factory NU l-ar acoperi).
|
||||
|
||||
Wrapam `init_db` astfel incat orice DB de test creat sa aiba id=1 pe Auto ON (held=0 la
|
||||
ingestie), pastrand suita verde ca inainte de 5.19. Conturile create explicit de teste
|
||||
@@ -114,7 +114,7 @@ def _reset_embeddings_singleton():
|
||||
|
||||
|
||||
def make_test_cui(seed: str = "") -> str:
|
||||
"""Factory centralizat (D#14, PRD 5.12 US-001): genereaza un CUI de test unic din seed.
|
||||
"""Factory centralizat: genereaza un CUI de test unic din seed.
|
||||
|
||||
Folosit de fixture-urile de test care creeaza conturi via /signup sau create_account
|
||||
si au nevoie de un CUI unic per test (altfel unicitatea CUI-ului bloca al doilea signup
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"""Teste US-003 (PRD 3.6): Acasa unificata — Trimiteri ca sectiune permanenta.
|
||||
"""Teste Acasa unificata — Trimiteri ca sectiune permanenta.
|
||||
|
||||
Tab-ul "Trimiteri" (coada) eliminat din tab-bar; Trimiterile devin o sectiune sub
|
||||
upload pe Acasa, cu heading "Trimiterile tale". ?tab=coada si /_fragments/coada
|
||||
servesc continutul Acasa (nu 404, nu fragment orfan). Poll aliniat la 15s (M5).
|
||||
servesc continutul Acasa (nu 404, nu fragment orfan).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -50,14 +50,14 @@ def _seed_submission(status: str = "sent", n: int = 1) -> None:
|
||||
|
||||
|
||||
def test_tab_bar_fara_trimiteri(client):
|
||||
"""US-009: tab-bar eliminat; 'Coada' nu exista; Mapari/Cont/Nomenclator raman in meniu."""
|
||||
"""Tab-bar eliminat; 'Coada' nu exista; Mapari/Cont/Nomenclator raman in meniu."""
|
||||
r = client.get("/")
|
||||
assert r.status_code == 200
|
||||
html = r.text
|
||||
# "Coada" nu trebuie sa existe nici ca tab, nici ca link in meniu
|
||||
assert 'id="tab-coada"' not in html
|
||||
assert 'href="/?tab=coada"' not in html
|
||||
# US-009: tab-bar eliminat; Mapari/Cont/Nomenclator sunt in meniul hamburger
|
||||
# Mapari/Cont/Nomenclator sunt in meniul hamburger
|
||||
for label in ("Mapari", "Cont", "Nomenclator"):
|
||||
assert f">{label}" in html or f"{label}<" in html, f"lipseste intrarea {label} in meniu"
|
||||
|
||||
@@ -70,8 +70,7 @@ def test_acasa_contine_sectiunea_trimiteri(client):
|
||||
html = r.text
|
||||
assert 'id="filtre-trimiteri"' in html
|
||||
assert "/_fragments/submissions" in html
|
||||
# PRD 5.9 US-003: detaliul s-a mutat in modalul global (#modal-detaliu); vechiul
|
||||
# panou inert #trimitere-detaliu a fost eliminat.
|
||||
# Detaliul e in modalul global (#modal-detaliu); panoul inert vechi eliminat.
|
||||
assert 'id="modal-detaliu"' in html
|
||||
assert 'id="trimitere-detaliu"' not in html
|
||||
|
||||
@@ -108,7 +107,7 @@ def test_acasa_fara_linkuri_ajutor(client):
|
||||
|
||||
|
||||
def test_acasa_fara_wayfinding_ajutor(client):
|
||||
"""US-001 (5.5): randul 'Ajutor' (wayfinding Mapari/Coduri RAR) eliminat din Acasa —
|
||||
"""Randul 'Ajutor' (wayfinding Mapari/Coduri RAR) eliminat din Acasa —
|
||||
navigarea traieste in tab-bar si in meniul de cont."""
|
||||
r = client.get("/?tab=acasa")
|
||||
html = r.text
|
||||
@@ -132,7 +131,7 @@ def test_trimiteri_fara_poll_periodic_pe_tabel(client):
|
||||
"""Tabelul de trimiteri NU se reimprospateaza periodic: #submissions-wrap se
|
||||
incarca la load / actiunile utilizatorului (trimiteriChanged) / reincarcaTrimiteri.
|
||||
Reimprospatarea automata la date noi externe se face prin pollerul de versiune
|
||||
care cheama reincarcaTrimiteri() — fara nudge manual (US-008)."""
|
||||
care cheama reincarcaTrimiteri()."""
|
||||
_seed_submission("sent")
|
||||
r = client.get("/?tab=acasa")
|
||||
html = r.text
|
||||
@@ -142,6 +141,6 @@ def test_trimiteri_fara_poll_periodic_pe_tabel(client):
|
||||
assert "every" not in wrap, f"tabelul nu trebuie sa aiba poll periodic: {wrap}"
|
||||
assert "reincarcaTrimiteri" in wrap
|
||||
assert "trimiteriChanged" in wrap
|
||||
# Pollerul de versiune exista (auto-refresh la date noi externe). Nudge eliminat (US-008).
|
||||
# Pollerul de versiune exista (auto-refresh la date noi externe); fara nudge manual.
|
||||
assert "/_fragments/trimiteri-versiune" in html
|
||||
assert 'id="nudge-trimiteri"' not in html
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-004 (PRD 5.5): model de stare a contului `accounts.status` + helperi.
|
||||
"""Teste model de stare a contului `accounts.status` + helperi.
|
||||
|
||||
Acopera: derivarea status din active la migrare, invariantul active=1 <=> status='active',
|
||||
helperii set_status/delete_account, protectia contului de sistem id=1, excluderea 'deleted'
|
||||
@@ -94,7 +94,7 @@ def test_delete_purjeaza_pii_si_elibereaza_cui(conn):
|
||||
"""Stergerea soft purjeaza creds RAR + revoca cheile API + elibereaza CUI (re-inregistrabil)."""
|
||||
from app.accounts import create_account, delete_account, list_accounts
|
||||
acct_id = create_account(conn, "Service GDPR", cui="RO12345", active=True)
|
||||
# US-013: creds in sloturi per-env (rar_creds_enc legacy dropata)
|
||||
# creds in sloturi per-env
|
||||
conn.execute(
|
||||
"UPDATE accounts SET rar_creds_test_enc='secret_enc_test', rar_creds_prod_enc='secret_enc_prod' WHERE id=?",
|
||||
(acct_id,),
|
||||
@@ -138,7 +138,6 @@ def test_migrare_deriva_status_din_active(conn):
|
||||
from app.db import _migrate
|
||||
|
||||
# Reconstruim accounts fara `status` (rebuild de tabela — singura cale in SQLite vechi).
|
||||
# US-013: rar_creds_enc nu mai exista in accounts (dropata); nu e in legacy DDL.
|
||||
conn.executescript(
|
||||
"""
|
||||
PRAGMA foreign_keys=OFF;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-001 (PRD 3.1): coloana accounts.active + helper-e cont in app/accounts.py."""
|
||||
"""Teste coloana accounts.active + helper-e cont in app/accounts.py."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -119,7 +119,7 @@ def test_list_accounts_ordonat_fara_creds(conn):
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# US-001 (PRD 5.12): accounts.email + validari companie/email/CUI
|
||||
# accounts.email + validari companie/email/CUI
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_create_account_fara_email_ridica(conn):
|
||||
@@ -176,7 +176,7 @@ def test_account_is_complete_false_pe_legacy_incomplet(conn):
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 5.17 US-001/US-008: schema tier + trial_until + set_tier + CLI set-tier
|
||||
# schema tier + trial_until + set_tier + CLI set-tier
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_migrare_tier_trial_defensiva(conn):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-008 (PRD 5.5): rute admin pentru ciclul de viata al conturilor —
|
||||
"""Rute admin pentru ciclul de viata al conturilor —
|
||||
block/archive/delete + bulk pe lista account_id, require_admin + CSRF + PRG, dev id=1 protejat.
|
||||
"""
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
"""Teste US-011 (PRD 3.3b): panou admin web /admin — conturi in asteptare + activare.
|
||||
|
||||
TDD strict: testele se scriu INAINTE de implementare; la inceput pica (RED),
|
||||
dupa implementare trec (GREEN).
|
||||
"""Teste panou admin web /admin — conturi in asteptare + activare.
|
||||
|
||||
Fisiere testate: app/web/admin_routes.py, app/web/templates/admin.html.
|
||||
"""
|
||||
@@ -175,7 +172,7 @@ def test_non_admin_403(client):
|
||||
Creeaza intai un cont admin (bootstrap: primul user devine admin),
|
||||
apoi un al doilea cont (non-admin) si verifica ca al doilea primeste 403.
|
||||
"""
|
||||
# Primul signup devine automat admin (bootstrap US-010)
|
||||
# Primul signup devine automat admin (bootstrap)
|
||||
_signup(client, "Admin Bootstrap SA", "bootstrap@test.ro")
|
||||
|
||||
# Al doilea user NU e admin
|
||||
@@ -286,7 +283,7 @@ def test_set_tier_din_admin_incheie_trial(client):
|
||||
"""POST /admin/set-tier -> tier actualizat, trial_until=NULL (trial incheiat), 303.
|
||||
|
||||
Contul nou are trial Pro 30z; alocarea manuala trebuie sa-l incheie ca alegerea
|
||||
sa aiba efect imediat (decizie user 2026-06-29)."""
|
||||
sa aiba efect imediat."""
|
||||
target_id = _signup(client, "Firma Upgrade SRL", "upgrade@test.ro")
|
||||
tier0, trial0 = _get_tier_trial(target_id)
|
||||
assert tier0 == "free", "cont nou trebuie sa porneasca pe free"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-010 (PRD 3.3b): rol admin + bootstrap + guard require_admin.
|
||||
"""Teste rol admin + bootstrap + guard require_admin.
|
||||
|
||||
Fisiere testate: app/users.py (helper-e admin), app/web/session.py (require_admin),
|
||||
tools/account.py (subcomanda set-admin).
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste API /v1/prezentari — rutare validare (T3) + idempotenta."""
|
||||
"""Teste API /v1/prezentari — rutare validare + idempotenta."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -63,7 +63,7 @@ def test_idempotenta_dedup(client):
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# PRD 5.7 — raspuns onest: erori/nemapate/motiv pe randuri blocate #
|
||||
# Raspuns onest: erori/nemapate/motiv pe randuri blocate #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
def test_needs_data_intoarce_erori(client):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-010 (PRD 5.6): API DELETE + re-pune in coada, scoped + oracol scope/stare."""
|
||||
"""Teste API DELETE + re-pune in coada, scoped + oracol scope/stare."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-005 — camp rar_env pe POST /v1/prezentari si /valideaza.
|
||||
"""Teste camp rar_env pe POST /v1/prezentari si /valideaza.
|
||||
|
||||
Acopera: default din cont, tinta explicita, respingere tinta indisponibila,
|
||||
echo GET, valoare invalida (422 Pydantic), echo dry-run valideaza.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""US-011 (PRD 5.15): account-scope pe GET-urile de listare API (securitate).
|
||||
"""Teste account-scope pe GET-urile de listare API (securitate).
|
||||
|
||||
Verifica:
|
||||
- GET /v1/prezentari: un cont nu vede submissions ale altui cont
|
||||
@@ -6,9 +6,8 @@ Verifica:
|
||||
- Unauthenticated access cu require_api_key=True -> 401
|
||||
- Filtre si paginare nu sparg scope-ul
|
||||
|
||||
Legatura cu implementare: resolve_account_id + account_scope_clause (mecanisme
|
||||
existente, reutilizate). Testele LOCK DOWN comportamentul deja implementat
|
||||
si verifica alinierea cu AUTOPASS_REQUIRE_API_KEY (dev vs prod).
|
||||
Foloseste resolve_account_id + account_scope_clause; verifica alinierea
|
||||
cu AUTOPASS_REQUIRE_API_KEY (dev vs prod).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -227,7 +226,7 @@ def test_get_listare_filtru_status_nu_sparge_scope(client):
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# PRD 5.17 — enforcement planuri: gate API (T4) + volum (T3) + kill-switch (T5)
|
||||
# Enforcement planuri: gate API + volum + kill-switch
|
||||
# ============================================================================
|
||||
|
||||
_PREZ_PLAN = {
|
||||
@@ -279,7 +278,7 @@ def _insert_n_submissions(account_id: int, n: int) -> None:
|
||||
def test_free_fara_api_403(client):
|
||||
"""Cont free (non-default, cu cheie API) → 403 PLAN_FARA_API pe POST /v1/prezentari.
|
||||
|
||||
T4 PRD 5.17: gate API refuza conturi cu api_access=False in PLANS.
|
||||
Gate-ul API refuza conturi cu api_access=False in PLANS.
|
||||
"""
|
||||
acct_id, key = _create_account_with_key("FreePlanGate")
|
||||
_set_tier_acct(acct_id, "free", trial_until=None)
|
||||
@@ -349,8 +348,8 @@ def test_trial_pro_api_ok(client):
|
||||
def test_dry_run_valideaza_ramane_permis(client):
|
||||
"""POST /v1/prezentari/valideaza (dry-run) e permis pe orice plan, inclusiv free.
|
||||
|
||||
Decizie design (PRD 5.17): valideaza nu face enqueue si nu consuma cota,
|
||||
deci NU e protejat de gate-ul API — integratorii pot testa fara upgrade.
|
||||
Valideaza nu face enqueue si nu consuma cota, deci NU e protejat de
|
||||
gate-ul API — integratorii pot testa fara upgrade.
|
||||
"""
|
||||
acct_id, key = _create_account_with_key("FreeValideazaTest")
|
||||
_set_tier_acct(acct_id, "free", trial_until=None)
|
||||
@@ -374,8 +373,8 @@ def test_dry_run_valideaza_ramane_permis(client):
|
||||
def test_free_peste_60_respins_api(client):
|
||||
"""Dev account (id=1) la 60/60 pe free → a 61-a prezentare respinsa 422 PLAN_LIMITA_LUNARA.
|
||||
|
||||
Dev account (id=1) in dev mode (require_api_key=False) are bypass la gate-ul API (T4),
|
||||
dar NU la verificarea de volum (T3). La 60/60, urmatoarea cerere trebuie respinsa 422.
|
||||
Dev account (id=1) in dev mode (require_api_key=False) are bypass la gate-ul API,
|
||||
dar NU la verificarea de volum. La 60/60, urmatoarea cerere trebuie respinsa 422.
|
||||
"""
|
||||
_set_tier_acct(1, "free", trial_until=None)
|
||||
_insert_n_submissions(1, 60)
|
||||
@@ -392,7 +391,7 @@ def test_free_peste_60_respins_api(client):
|
||||
def test_eroare_3_niveluri_plan_limita(client):
|
||||
"""Eroarea PLAN_LIMITA_LUNARA contine toate 3 nivelurile: cod, problema, cauza, fix.
|
||||
|
||||
Pattern standard (PRD 5.17): eroare structurata pe 3 niveluri — nu 500, nu catch-all.
|
||||
Pattern standard de eroare structurata pe 3 niveluri — nu 500, nu catch-all.
|
||||
"""
|
||||
_set_tier_acct(1, "free", trial_until=None)
|
||||
_insert_n_submissions(1, 60)
|
||||
@@ -512,7 +511,7 @@ def test_dev_id1_neblocat(client):
|
||||
def test_flag_enforce_plans_false_sare_enforcement(client, monkeypatch):
|
||||
"""Kill-switch AUTOPASS_ENFORCE_PLANS=false sare toate gate-urile de plan.
|
||||
|
||||
T5 PRD 5.17: flag de operare pentru debugging sau rollback rapid fara revert de cod.
|
||||
Flag de operare pentru debugging sau rollback rapid fara revert de cod.
|
||||
Chiar si cu free la 60/60, nu trebuie 422 cand flag-ul e oprit.
|
||||
"""
|
||||
from app.config import get_settings
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-004 (PRD 5.6): audit cerere API per cont in jurnal."""
|
||||
"""Teste audit cerere API per cont in jurnal."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""US-001 (PRD 5.19): schema comutator Auto per cont + flag `held` pe submission.
|
||||
"""Schema comutator Auto per cont + flag `held` pe submission.
|
||||
|
||||
Acopera: migrarea aditiva idempotenta (coloane + index partial pe DB vechi), helperii
|
||||
`get_auto_send`/`set_auto_send`/`held_for_account` din app/accounts.py si default-ul 0.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"""Teste US-007 (PRD 3.6) actualizate dupa US-002 (PRD 5.11).
|
||||
"""Teste comutator auto_send: macro autosend_toggle neutralizat (intoarce string gol).
|
||||
|
||||
US-002: macro autosend_toggle neutralizat (intoarce string gol).
|
||||
Checkbox-ul name=auto_send a fost scos din UI. Coloanele DB raman.
|
||||
Testele de UI verifica ABSENTA toggle-ului; testele de backend (stocare DB) raman.
|
||||
"""
|
||||
@@ -97,24 +96,24 @@ def _macro_html(checked: bool = True, form_id: str = "") -> str:
|
||||
return str(mod.autosend_toggle(form_id=form_id, checked=checked))
|
||||
|
||||
|
||||
# --- markup: macro neutralizat dupa US-002 ---
|
||||
# --- markup: macro neutralizat ---
|
||||
|
||||
def test_comutator_coada_prezent():
|
||||
"""US-002: macro autosend_toggle neutralizat -> output gol (fara checkbox)."""
|
||||
"""macro autosend_toggle neutralizat -> output gol (fara checkbox)."""
|
||||
html = _macro_html()
|
||||
assert 'name="auto_send"' not in html, "US-002: checkbox auto_send scos din UI"
|
||||
assert 'name="auto_send"' not in html, "checkbox auto_send scos din UI"
|
||||
assert html.strip() == "", f"macro neutralizat trebuie sa intoarca string gol, got: {html!r}"
|
||||
|
||||
|
||||
def test_eticheta_scoped_pe_operatie():
|
||||
"""US-002: macro neutralizat -> nicio eticheta scoped."""
|
||||
"""macro neutralizat -> nicio eticheta scoped."""
|
||||
html = _macro_html()
|
||||
assert "aceasta operatie" not in html
|
||||
assert html.strip() == ""
|
||||
|
||||
|
||||
def test_default_pune_automat():
|
||||
"""US-002: macro neutralizat intoarce gol indiferent de parametrul checked."""
|
||||
"""macro neutralizat intoarce gol indiferent de parametrul checked."""
|
||||
html_default = _macro_html(checked=True)
|
||||
assert html_default.strip() == ""
|
||||
html_off = _macro_html(checked=False)
|
||||
@@ -154,7 +153,7 @@ def test_tine_pentru_verificare_mapeaza_auto_send_false(client):
|
||||
# --- prezent in AMBELE locuri (mapari tab + panou preview) ---
|
||||
|
||||
def test_comutator_in_tab_mapari(client):
|
||||
"""US-002: tabul Mapari nu mai contine checkbox auto_send (macro neutralizat)."""
|
||||
"""Tabul Mapari nu mai contine checkbox auto_send (macro neutralizat)."""
|
||||
from app.db import get_connection
|
||||
import json
|
||||
acct = _create_account_user("tm@test.com")
|
||||
@@ -172,12 +171,12 @@ def test_comutator_in_tab_mapari(client):
|
||||
_login(client, "tm@test.com")
|
||||
resp = client.get("/?tab=mapari")
|
||||
assert resp.status_code == 200
|
||||
assert 'name="auto_send"' not in resp.text, "US-002: checkbox auto_send scos din UI"
|
||||
assert "In coada" not in resp.text, "US-002: coloana 'In coada' scoasa"
|
||||
assert 'name="auto_send"' not in resp.text, "checkbox auto_send scos din UI"
|
||||
assert "In coada" not in resp.text, "coloana 'In coada' scoasa"
|
||||
|
||||
|
||||
def test_comutator_in_panou_preview(client):
|
||||
"""US-002: panoul de mapare din preview nu mai contine checkbox auto_send."""
|
||||
"""Panoul de mapare din preview nu mai contine checkbox auto_send."""
|
||||
_create_account_user("pp@test.com")
|
||||
_seed_nomenclator("R-FRANE")
|
||||
_login(client, "pp@test.com")
|
||||
@@ -203,5 +202,5 @@ def test_comutator_in_panou_preview(client):
|
||||
})
|
||||
assert r.status_code == 200
|
||||
assert "OP-NEMAPAT" in r.text, "operatia nemapata trebuie sa apara in panoul de mapare"
|
||||
assert 'name="auto_send"' not in r.text, "US-002: checkbox auto_send scos din preview"
|
||||
assert "In coada automat" not in r.text, "US-002: eticheta 'In coada automat' scoasa"
|
||||
assert 'name="auto_send"' not in r.text, "checkbox auto_send scos din preview"
|
||||
assert "In coada automat" not in r.text, "eticheta 'In coada automat' scoasa"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-010 (PRD 5.20): badge mediu RAR in liste/detaliu/audit/ecou API.
|
||||
"""Teste badge mediu RAR in liste/detaliu/audit/ecou API.
|
||||
|
||||
Teste:
|
||||
test_badge_in_lista -- /_fragments/submissions afiseaza PRODUCȚIE / Testare per rand
|
||||
|
||||
@@ -137,7 +137,7 @@ def test_legacy_dual_lookup_strategy():
|
||||
assert found, "dual-lookup trebuie sa gaseasca randul vechi"
|
||||
|
||||
|
||||
# --- Integrare: API route foloseste build_key (OV-2) ---
|
||||
# --- Integrare: API route foloseste build_key ---
|
||||
|
||||
@pytest.fixture()
|
||||
def client(monkeypatch):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste PRD 5.19 R4 — tools/carantina_held.py (atenuare hazard de rollback).
|
||||
"""Teste tools/carantina_held.py (atenuare hazard de rollback).
|
||||
|
||||
Carantineaza randurile `queued AND held=1` (-> `error`/`ROLLBACK_QUARANTINE`)
|
||||
ca sa nu fie trimise de un worker fara filtrul `AND held=0` dupa un revert.
|
||||
@@ -63,7 +63,7 @@ def test_carantineaza_rand_tinut(env, capsys):
|
||||
r = _row(conn, sid)
|
||||
assert r["status"] == "error"
|
||||
assert r["rar_error"] == "ROLLBACK_QUARANTINE"
|
||||
# /code-review #4: randul carantinat primeste purge_after (altfel PII ar sta la nesfarsit,
|
||||
# randul carantinat primeste purge_after (altfel PII ar sta la nesfarsit,
|
||||
# purge_expired sterge doar randuri cu purge_after setat).
|
||||
assert r["purge_after"] is not None
|
||||
assert conn.execute(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-008 (PRD 5.20): configurare medii RAR per cont — Testare + Productie.
|
||||
"""Teste configurare medii RAR per cont — Testare + Productie.
|
||||
|
||||
Ruta testata: POST /cont/rar-medii
|
||||
|
||||
|
||||
@@ -47,12 +47,12 @@ def _body(**over):
|
||||
def test_dashboard_renders_with_rar_state(client):
|
||||
r = client.get("/")
|
||||
assert r.status_code == 200
|
||||
# Dupa US-003 bara de status e incarcata via HTMX (hx-trigger=load, every 15s)
|
||||
# Bara de status e incarcata via HTMX (hx-trigger=load, every 15s)
|
||||
assert "/_fragments/status" in r.text, "Dashboard-ul trebuie sa referenceze fragmentul de status"
|
||||
# Fragmentul de status contine starea de sanatate (text uman, nu brut tehnic)
|
||||
rs = client.get("/_fragments/status")
|
||||
assert rs.status_code == 200
|
||||
# US-003 D6: strip sanatate unificat — "declaratiile" apare in orice stare (curg/blocat)
|
||||
# strip sanatate unificat — "declaratiile" apare in orice stare (curg/blocat)
|
||||
assert "declaratiile" in rs.text.lower(), (
|
||||
f"Strip sanatate lipseste din fragment. HTML: {rs.text[:500]}"
|
||||
)
|
||||
@@ -73,7 +73,7 @@ def test_nomenclator_fragment_lists_seed(client):
|
||||
def test_submissions_fragment_empty_state(client):
|
||||
r = client.get("/_fragments/submissions")
|
||||
assert r.status_code == 200
|
||||
# US-005: empty state prietenos cu indemn la Import (nu mesajul tehnic vechi)
|
||||
# empty state prietenos cu indemn la Import (nu mesajul tehnic vechi)
|
||||
assert "Nicio trimitere" in r.text or "incepe cu Import" in r.text or "?tab=import" in r.text
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""Test US-011 (discoverability): linkul 'Panou admin' apare pe dashboard doar pentru admini.
|
||||
"""Linkul 'Panou admin' apare pe dashboard doar pentru admini.
|
||||
|
||||
Completeaza intentia US-011 — adminul trebuie sa poata descoperi /admin din UI, nu doar
|
||||
prin URL direct.
|
||||
Adminul trebuie sa poata descoperi /admin din UI, nu doar prin URL direct.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Teste US-005 (PRD 3.3): scoping dashboard pe sesiune (2 conturi, citiri).
|
||||
"""Teste scoping dashboard pe sesiune (2 conturi, citiri).
|
||||
|
||||
Comportamental (C6): nu grep, ci verificare reala cu 2 conturi + date distincte.
|
||||
Verificare comportamentala reala cu 2 conturi + date distincte, nu grep.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-012 (PRD 5.6): un rand `error` nu mai blocheaza retrimiterea (dedup).
|
||||
"""Un rand `error` nu mai blocheaza retrimiterea (dedup).
|
||||
|
||||
La resubmit cu aceeasi cheie de continut peste un rand `error`: se RE-ACTIVEAZA
|
||||
(reactivated:true + stare noua), creds-urile se actualizeaza. Peste sent/queued/
|
||||
@@ -82,7 +82,7 @@ def test_resubmit_actualizeaza_creds_pe_reactivare(client):
|
||||
enc_dupa = _creds_enc(sid)
|
||||
assert enc_dupa is not None
|
||||
assert enc_dupa != enc_initial, "creds-urile trebuie actualizate la reactivare"
|
||||
# US-013: creds propagate in slotul per-env (rar_creds_test_enc, ancora globala=test)
|
||||
# creds propagate in slotul per-env (rar_creds_test_enc, ancora globala=test)
|
||||
from app.db import get_connection
|
||||
from app.crypto import decrypt_creds
|
||||
conn = get_connection()
|
||||
@@ -118,7 +118,7 @@ def test_resubmit_peste_queued_ramane_deduped(client):
|
||||
|
||||
|
||||
def test_reactivare_pe_needs_data_expune_erori(client):
|
||||
"""PRD 5.7: reactivarea unui rand error care re-clasifica needs_data trebuie sa
|
||||
"""Reactivarea unui rand error care re-clasifica needs_data trebuie sa
|
||||
expuna erori/motiv (raspuns onest), nu doar status + reactivated."""
|
||||
# rand initial valid -> queued; il fortam error
|
||||
r1 = client.post("/v1/prezentari", json=_body())
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
"""Teste US-012 (PRD 5.15): Analytics device-mix — validare premisa mobil, fara PII.
|
||||
|
||||
TDD: RED inainte de implementare.
|
||||
"""Teste analytics device-mix — validare premisa mobil, fara PII.
|
||||
|
||||
Semnal: la acces dashboard -> eveniment 'device_mix' in app_events cu cod 'desktop'/'mobil'.
|
||||
Zero PII: nu se stocheaza UA brut, IP sau VIN.
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
"""Teste US-012 (PRD 5.20): audit evenimente medii RAR + e2e lant submission.
|
||||
|
||||
Fisier nou; nu modifica teste existente.
|
||||
"""Teste audit evenimente medii RAR + e2e lant submission.
|
||||
|
||||
Teste:
|
||||
test_lant_import_pana_la_queued -- submission ajunge la status=queued cu rar_env corect
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""US-005 (PRD 5.18) — embeddings indexeaza corpusul etichetat (NU nomenclatorul).
|
||||
"""Embeddings indexeaza corpusul etichetat (NU nomenclatorul).
|
||||
|
||||
k-NN peste exemple reale etichetate (denumire_normalizata -> cod, is_nul) e net mai
|
||||
precis decat peste cele 18 categorii generice. Acopera si simetria corpus/query (F1):
|
||||
precis decat peste cele 18 categorii generice. Acopera si simetria corpus/query:
|
||||
corpusul e text NORMALIZAT, deci query-ul trebuie normalizat la fel inainte de embedding.
|
||||
"""
|
||||
|
||||
@@ -34,7 +34,7 @@ def env(monkeypatch):
|
||||
tmp = tempfile.mkdtemp()
|
||||
monkeypatch.setenv("AUTOPASS_DB_PATH", os.path.join(tmp, "us005.db"))
|
||||
monkeypatch.setenv("AUTOPASS_WEB_AUTH_REQUIRED", "false")
|
||||
monkeypatch.setenv("AUTOPASS_EMBEDDINGS_ENABLED", "true") # US-005 are nevoie de embeddings ON
|
||||
monkeypatch.setenv("AUTOPASS_EMBEDDINGS_ENABLED", "true") # necesar pentru testele de embeddings
|
||||
from app.config import get_settings
|
||||
get_settings.cache_clear()
|
||||
from app.db import init_db
|
||||
@@ -115,7 +115,7 @@ def test_semnatura_corpus_pe_seed(conn):
|
||||
|
||||
|
||||
def test_query_normalizat_ca_si_corpusul(conn, monkeypatch):
|
||||
"""F1 (HIGH): enrich_suggestions interogheaza suggest_nearest cu textul NORMALIZAT."""
|
||||
"""enrich_suggestions interogheaza suggest_nearest cu textul NORMALIZAT."""
|
||||
import app.embeddings as emb
|
||||
captura = {}
|
||||
monkeypatch.setattr(emb, "has_corpus", lambda: True)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"""US-006 (PRD 5.18) — enrich_suggestions = pre-filtru NUL + k-NN pe corpus etichetat.
|
||||
"""enrich_suggestions = pre-filtru NUL + k-NN pe corpus etichetat.
|
||||
|
||||
Ordinea de precedenta: pre-filtru NUL -> (daca NUL: fara cod) altfel GOLD partajat >
|
||||
exact (SILVER) > k-NN embeddings. k-NN sub prag -> abtinere. Vecin k-NN NUL -> supresie.
|
||||
Invariant #13: nimic din asta nu intra in resolve_prestatii/load_mapping.
|
||||
Nimic din enrich_suggestions nu intra in resolve_prestatii/load_mapping.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -123,7 +123,7 @@ def test_vecin_knn_nul_supreseaza(conn, monkeypatch):
|
||||
|
||||
|
||||
def test_invariant_13_resolve_neatins(conn):
|
||||
"""Regresie #13: SILVER populat NU produce auto-rezolvare in resolve_prestatii."""
|
||||
"""SILVER populat NU produce auto-rezolvare in resolve_prestatii."""
|
||||
from app.mapping import resolve_prestatii, normalize_for_match
|
||||
_silver(conn, normalize_for_match("OPERATIE X"), "OE-1")
|
||||
resolved, unmapped = resolve_prestatii(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-001 (PRD 5.6): handler global de excepții -> 500 structurat (3 niveluri) + log."""
|
||||
"""Teste handler global de exceptii -> 500 structurat (3 niveluri) + log."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -39,7 +39,7 @@ def test_exceptie_neasteptata_da_500_structurat(client, monkeypatch):
|
||||
assert r.status_code == 500
|
||||
body = r.json()
|
||||
assert body["cod"] == "EROARE_INTERNA"
|
||||
# 3 niveluri (PRD 5.4): problema + fix
|
||||
# 3 niveluri: cod + problema + fix
|
||||
assert body["problema"]
|
||||
assert body["fix"]
|
||||
assert "request_id" in body
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
"""Teste pentru app/errors.py — catalog central de erori (US-001 / PRD 5.4).
|
||||
|
||||
Urmeaza TDD: testele sunt scrise INAINTE de implementare.
|
||||
"""
|
||||
"""Teste pentru app/errors.py — catalog central de erori."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""US-002 (PRD 5.18) — etichetator offline multi-backend cu prompt procedural.
|
||||
"""Etichetator offline multi-backend cu prompt procedural.
|
||||
|
||||
Toate testele ruleaza FARA retea reala (transport injectabil / inspectie body).
|
||||
Acopera: prompt 3 pasi, envelope json_schema strict + enum, backend selectabil
|
||||
@@ -70,7 +70,7 @@ def test_parseaza_raspuns_si_garda_truncare():
|
||||
|
||||
|
||||
def test_backend_selectabil_env(monkeypatch):
|
||||
# Default = lmstudio (backend aprobat v1, D4).
|
||||
# Default = lmstudio.
|
||||
monkeypatch.delenv("ETICHETARE_BACKEND", raising=False)
|
||||
assert eticheteaza.get_backend().name == "lmstudio"
|
||||
# Selectie prin env.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-006 (PRD 3.6): "Formate de coloane salvate" randate ca TABEL.
|
||||
"""Teste "Formate de coloane salvate" randate ca TABEL.
|
||||
|
||||
Doar marcaj de template — POST-urile /formate-coloane/editeaza si /formate-coloane/sterge
|
||||
raman identice. .tablewrap pentru consistenta cu celelalte tabele.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste FOUNDATION (Task #1): schema + migrari idempotente + openpyxl disponibil."""
|
||||
"""Teste schema + migrari idempotente + openpyxl disponibil."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -35,11 +35,11 @@ def _tables(conn) -> set[str]:
|
||||
# --- Coloane noi ---
|
||||
|
||||
def test_accounts_rar_creds_enc_dropata(db_conn):
|
||||
"""US-013: accounts.rar_creds_enc a fost dropata; submissions.rar_creds_enc ramane."""
|
||||
"""accounts.rar_creds_enc a fost dropata; submissions.rar_creds_enc ramane."""
|
||||
acc_cols = _table_cols(db_conn, "accounts")
|
||||
sub_cols = _table_cols(db_conn, "submissions")
|
||||
assert "rar_creds_enc" not in acc_cols, \
|
||||
"accounts.rar_creds_enc trebuie sa fie ABSENTA dupa US-013 DROP"
|
||||
"accounts.rar_creds_enc trebuie sa fie ABSENTA"
|
||||
assert "rar_creds_enc" in sub_cols, \
|
||||
"submissions.rar_creds_enc trebuie sa RAMANA (creds efemere per-cerere)"
|
||||
|
||||
@@ -158,7 +158,7 @@ def test_migrate_on_existing_db(monkeypatch):
|
||||
assert "batch_id" in sub_cols
|
||||
assert "row_index" in sub_cols
|
||||
assert "purge_after" in sub_cols
|
||||
# US-013: accounts.rar_creds_enc a fost dropata.
|
||||
# accounts.rar_creds_enc a fost dropata.
|
||||
assert "rar_creds_enc" not in acc_cols
|
||||
conn.close()
|
||||
get_settings.cache_clear()
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
"""US-003 (PRD 5.18) — generare seed etichetat in faze pe frecventa.
|
||||
"""Generare seed etichetat in faze pe frecventa.
|
||||
|
||||
Pipeline dedup OBLIGATORIU inainte de orice apel LLM (D5):
|
||||
Pipeline dedup OBLIGATORIU inainte de orice apel LLM:
|
||||
brut -> normalize_for_match -> arunca chei vide -> dedup pe cheie (freq=suma NR)
|
||||
-> reuse etichete existente (labels-groq + seed comis, conflict freq-max) -> de_etichetat.
|
||||
|
||||
Idempotenta cross-run (F2/F7): a doua rulare consuma seedul comis ca cache -> 0 apeluri LLM.
|
||||
Idempotenta cross-run: a doua rulare consuma seedul comis ca cache -> 0 apeluri LLM.
|
||||
Toate testele FARA retea: `clasifica` e injectat (mock care inregistreaza ce primeste).
|
||||
"""
|
||||
|
||||
@@ -134,7 +134,7 @@ def test_zero_duplicate_trimis_la_llm(tmp_path):
|
||||
|
||||
|
||||
def test_rerun_zero_apeluri_llm(tmp_path):
|
||||
"""Criteriul real de idempotenta (F2/F7): a doua rulare = 0 apeluri LLM, seed identic."""
|
||||
"""Criteriul real de idempotenta: a doua rulare = 0 apeluri LLM, seed identic."""
|
||||
f = tmp_path / "a.csv"
|
||||
_scrie_csv(f, [("OP UNU", 10), ("OP DOI", 5)])
|
||||
seed = tmp_path / "seed.json"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste scope cont pe GET /v1/audit/export (US-003, PRD 3.2)."""
|
||||
"""Teste scope cont pe GET /v1/audit/export."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -51,7 +51,7 @@ def test_export_doar_contul_cheii(env):
|
||||
from app.db import get_connection
|
||||
conn = get_connection()
|
||||
try:
|
||||
# tier='pro' ca sa treaca gate-ul API (T4 PRD 5.17); testul masoara scoping, nu planuri.
|
||||
# tier='pro' ca sa treaca gate-ul API; testul masoara scoping, nu planuri.
|
||||
conn.execute("INSERT INTO accounts (id, name, tier) VALUES (2, 'al-doilea', 'pro')")
|
||||
k1 = create_api_key(conn, 1)
|
||||
k2 = create_api_key(conn, 2)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Teste scope cont pe GET /v1/mapari + /pending (US-002, PRD 3.2).
|
||||
"""Teste scope cont pe GET /v1/mapari + /pending.
|
||||
|
||||
TD-3.2 (decis la poarta): parametrul ?account_id= din query se pastreaza DAR:
|
||||
Parametrul ?account_id= din query se pastreaza DAR:
|
||||
- daca e prezent SI difera de contul cheii -> 400 explicit
|
||||
- daca e prezent si egal -> ok
|
||||
- daca lipseste -> contul cheii
|
||||
@@ -69,7 +69,7 @@ def test_mapari_doar_contul_cheii(env):
|
||||
|
||||
|
||||
def test_mapari_query_account_id_diferit_400(env):
|
||||
"""Daca ?account_id difera de contul cheii -> 400 explicit (TD-3.2)."""
|
||||
"""Daca ?account_id difera de contul cheii -> 400 explicit."""
|
||||
with _client() as c:
|
||||
from app.auth import create_api_key
|
||||
from app.db import get_connection
|
||||
@@ -85,7 +85,7 @@ def test_mapari_query_account_id_diferit_400(env):
|
||||
|
||||
|
||||
def test_mapari_query_account_id_egal_ok(env):
|
||||
"""Daca ?account_id egal cu contul cheii -> 200 (TD-3.2)."""
|
||||
"""Daca ?account_id egal cu contul cheii -> 200."""
|
||||
with _client() as c:
|
||||
from app.auth import create_api_key
|
||||
from app.db import get_connection
|
||||
@@ -161,7 +161,7 @@ def test_pending_web_global_neschimbat(env):
|
||||
|
||||
|
||||
def test_pending_filtreaza_in_sql_cu_regula_null(env):
|
||||
"""B1: pending_unmapped(conn, account_id=1) include si randuri cu account_id=NULL (legacy).
|
||||
"""pending_unmapped(conn, account_id=1) include si randuri cu account_id=NULL (legacy).
|
||||
|
||||
Filtrarea trebuie sa se faca IN SQL cu:
|
||||
WHERE status='needs_mapping' AND (account_id=? OR (account_id IS NULL AND ?=1))
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
"""Teste scope cont pe GET /v1/prezentari + /{id} (US-001, PRD 3.2).
|
||||
|
||||
Metoda TDD: testele se scriu inainte de implementare (RED) si trebuie sa ramana
|
||||
verzi dupa implementare (GREEN).
|
||||
"""
|
||||
"""Teste scope cont pe GET /v1/prezentari + /{id}."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -47,7 +43,7 @@ def test_lista_doar_contul_cheii(env):
|
||||
from app.db import get_connection
|
||||
conn = get_connection()
|
||||
try:
|
||||
# tier='pro' pe ambele conturi — testul verifica scoping GET, nu planuri (T4 PRD 5.17).
|
||||
# tier='pro' pe ambele conturi — testul verifica scoping GET, nu planuri.
|
||||
conn.execute("UPDATE accounts SET tier='pro' WHERE id=1")
|
||||
conn.execute("INSERT INTO accounts (id, name, tier) VALUES (2, 'al-doilea', 'pro')")
|
||||
k1 = create_api_key(conn, 1)
|
||||
@@ -77,7 +73,7 @@ def test_lista_doar_contul_cheii(env):
|
||||
def test_detaliu_cross_account_404(env):
|
||||
"""GET /{id} cu cheia contului B pentru submission-ul contului A -> 404.
|
||||
|
||||
B3: detail-ul 404 cross-account trebuie byte-identic cu cel al unui id inexistent
|
||||
Raspunsul 404 cross-account trebuie byte-identic cu cel al unui id inexistent
|
||||
(acelasi status + acelasi mesaj) — nu dam indicii ca randul exista.
|
||||
"""
|
||||
with _client() as c:
|
||||
@@ -103,7 +99,7 @@ def test_detaliu_cross_account_404(env):
|
||||
|
||||
|
||||
def test_legacy_null_vizibil_pentru_cont_1(env):
|
||||
"""Randuri cu account_id=NULL apartin contului 1 (legacy OV-2); contul 2 nu le vede."""
|
||||
"""Randuri cu account_id=NULL apartin contului 1 (legacy); contul 2 nu le vede."""
|
||||
with _client() as c:
|
||||
from app.auth import create_api_key
|
||||
from app.db import get_connection
|
||||
@@ -149,11 +145,11 @@ def test_fara_cheie_flag_off_vede_contul_1(env):
|
||||
|
||||
|
||||
def test_detaliu_nu_expune_creds(env):
|
||||
"""B4: GET /v1/prezentari/{id} nu expune campuri sensibile (rar_creds_enc, payload_json,
|
||||
"""GET /v1/prezentari/{id} nu expune campuri sensibile (rar_creds_enc, payload_json,
|
||||
idempotency_key).
|
||||
|
||||
NOTA T9 (PRD 5.6): `rar_error` e ACUM expus intentionat (recovery API observabil) —
|
||||
contine doar coduri/mesaje de validare RAR, niciodata creds.
|
||||
`rar_error` e expus intentionat (recovery API observabil) — contine doar
|
||||
coduri/mesaje de validare RAR, niciodata creds.
|
||||
"""
|
||||
with _client() as c:
|
||||
from app.auth import create_api_key
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste PRD 5.19 US-010 — onestitate + observabilitate `held` pe canalul API.
|
||||
"""Onestitate + observabilitate `held` pe canalul API.
|
||||
|
||||
- `held` in raspunsul enqueue (SubmissionResult) + motiv non-null.
|
||||
- `held` in proiectiile GET /v1/prezentari si /v1/prezentari/{id}.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Teste PRD 5.19 US-002 — snapshot `held` la ingestie din comutatorul de cont.
|
||||
"""Teste snapshot `held` la ingestie din comutatorul de cont.
|
||||
|
||||
Acopera TOATE situ-rile care scriu `status='queued'` prin ingestie (chokepoint
|
||||
Acopera TOATE situatiile care scriu `status='queued'` prin ingestie (chokepoint
|
||||
`held_for_account`): enqueue API, reactivare error->queued, dedup echo, commit import,
|
||||
reresolve `needs_mapping`. `held` NU intra in idempotency_key.
|
||||
|
||||
@@ -107,7 +107,7 @@ def test_auto_on_ingestie_not_held(client):
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Reactivare error->queued (bug de bypass Eng Finding A) #
|
||||
# Reactivare error->queued #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
def test_reactivare_respecta_auto_off(client):
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
"""Regresie PRD 5.19 US-002 — re-snapshot `held` pe caile de re-punere in coada.
|
||||
"""Regresie — re-snapshot `held` pe caile de re-punere in coada.
|
||||
|
||||
Bug (gasit la /code-review high): create_prezentari (reactivare) si reresolve_account
|
||||
re-calculau `held` din comutatorul contului la tranzitia -> queued, dar caile de
|
||||
re-punere din dashboard/admin (requeue_submission, corectie, repune-cu-cod, bulk-fix)
|
||||
lasau `held` pe valoarea VECHE. Consecinta: un rand ingerat pe Auto ON (held=0) care a
|
||||
Bug: create_prezentari (reactivare) si reresolve_account re-calculau `held` din
|
||||
comutatorul contului la tranzitia -> queued, dar caile de re-punere din
|
||||
dashboard/admin (requeue_submission, corectie, repune-cu-cod, bulk-fix) lasau
|
||||
`held` pe valoarea VECHE. Consecinta: un rand ingerat pe Auto ON (held=0) care a
|
||||
esuat, apoi contul trecut pe Auto OFF, la re-punere pastra held=0 -> worker-ul il
|
||||
auto-trimitea la RAR (FINALIZATA ireversibil) desi contul e Auto OFF.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste TDD pentru tools/mapare-llm/heldout_eval.py (L14-S5).
|
||||
"""Teste pentru tools/mapare-llm/heldout_eval.py.
|
||||
|
||||
Fixture sintetic cu predictii+ground_truth cunoscute. Verifica:
|
||||
- precizie globala
|
||||
@@ -398,8 +398,7 @@ class TestExportForLabeling:
|
||||
for row in reader:
|
||||
# Coloana cod_gold trebuie sa fie vida (nu etichetata de cod!)
|
||||
assert row["cod_gold"] == "", (
|
||||
"cod_gold nu trebuie pre-completat: ar fi 'antrenare pe test' "
|
||||
"(Decision #19 PRD 5.14)"
|
||||
"cod_gold nu trebuie pre-completat: ar fi 'antrenare pe test'"
|
||||
)
|
||||
|
||||
def test_n_randuri_egal_cu_sample(self, tmp_path):
|
||||
@@ -413,7 +412,7 @@ class TestExportForLabeling:
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Sectiunea 8: kill_criterion — pragul de acceptanta (F-E, PRD 5.14)
|
||||
# Sectiunea 8: kill_criterion — pragul de acceptanta
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestKillCriterion:
|
||||
@@ -424,8 +423,8 @@ class TestKillCriterion:
|
||||
|
||||
Justificare threshold 0.5% (0.005):
|
||||
Un service cu 200 operatii/zi auto-rezolvate = 1 FINALIZATA gresita/zi.
|
||||
FINALIZATA e ireversibila (cf. PRD 5.14 Premisa 3 / invariant CLAUDE.md).
|
||||
Pragul poate fi RELAXAT empiric; nu INASPRIT post-hoc (sesizare-in-timp).
|
||||
FINALIZATA e ireversibila.
|
||||
Pragul poate fi RELAXAT empiric; nu INASPRIT post-hoc.
|
||||
"""
|
||||
|
||||
def test_trece_cand_sub_prag(self):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""US-003 (PRD 5.20): build_key incorporeaza rar_env."""
|
||||
"""build_key incorporeaza rar_env."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
"""Teste API import Treapta 2 — POST /v1/import, preview, commit, export-failed.
|
||||
"""Teste API import — POST /v1/import, preview, commit, export-failed.
|
||||
|
||||
Acopera:
|
||||
- #11 U1+T4: upload + staging + mapare coloane semnatura/drift/fuzzy
|
||||
- #12 T2+T11: preview 6 stari + already_sent batch lookup + intra-batch collision
|
||||
- #13 T5+T12: gate HARD confirmare + atestare valori + commit ON CONFLICT (TOCTOU)
|
||||
- #14 T8: export randuri esuate CSV
|
||||
- upload + staging + mapare coloane semnatura/drift/fuzzy
|
||||
- preview 6 stari + already_sent batch lookup + intra-batch collision
|
||||
- gate HARD confirmare + atestare valori + commit ON CONFLICT (TOCTOU)
|
||||
- export randuri esuate CSV
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -91,15 +91,11 @@ def _default_column_mapping() -> dict:
|
||||
|
||||
def _setup_nomenclator(client: TestClient) -> None:
|
||||
"""Seed nomenclator cu un cod de prestatie pentru teste."""
|
||||
# Folosim POST /v1/prezentari pentru a forta seed-ul nomenclatorului
|
||||
# care are loc in init_db -> seed_nomenclator_if_empty
|
||||
pass # seed-ul se face automat in init_db
|
||||
|
||||
|
||||
def _seed_operation_mapping(client: TestClient, cod_op: str = "Revizie", cod_prest: str = "OE-1") -> None:
|
||||
"""Salveaza o mapare de operatii pentru teste."""
|
||||
# Adauga mai intai in nomenclator daca nu exista (prin POST prezentare care creeaza cod)
|
||||
# De fapt, cod OE-1 e in nomenclatorul seed
|
||||
client.post("/v1/mapari", json={
|
||||
"cod_op_service": cod_op,
|
||||
"cod_prestatie": cod_prest,
|
||||
@@ -108,7 +104,7 @@ def _seed_operation_mapping(client: TestClient, cod_op: str = "Revizie", cod_pre
|
||||
|
||||
|
||||
# =========================================================================== #
|
||||
# #11 — Upload + staging (U1+T4) #
|
||||
# Upload + staging #
|
||||
# =========================================================================== #
|
||||
|
||||
class TestUploadStaging:
|
||||
@@ -144,7 +140,7 @@ class TestUploadStaging:
|
||||
assert r.status_code == 422
|
||||
|
||||
def test_issue5a_raw_json_criptat(self, client):
|
||||
"""Issue 5a: raw_json din import_rows trebuie sa fie criptat (ciphertext la rest)."""
|
||||
"""raw_json din import_rows trebuie sa fie criptat (ciphertext la rest)."""
|
||||
data = _make_xlsx([_HEADER, _ROW_OK])
|
||||
r = _upload_file(client, data, "test.xlsx")
|
||||
assert r.status_code == 200
|
||||
@@ -173,7 +169,7 @@ class TestUploadStaging:
|
||||
conn.close()
|
||||
|
||||
def test_issue5b_fuzzy_coloane_refoloseste_normalize_for_match(self, client):
|
||||
"""Issue 5b: fuzzy_suggestions din raspuns foloseste normalize_for_match (fara duplicat)."""
|
||||
"""fuzzy_suggestions din raspuns foloseste normalize_for_match (fara duplicat)."""
|
||||
data = _make_xlsx([_HEADER, _ROW_OK])
|
||||
r = _upload_file(client, data, "test.xlsx")
|
||||
assert r.status_code == 200
|
||||
@@ -190,7 +186,7 @@ class TestUploadStaging:
|
||||
assert "odometru_final" in camps, f"'odometru_final' trebuie in sugestii"
|
||||
|
||||
def test_drift_semnatura_coloane(self, client):
|
||||
"""T4/D3: upload 2 cu coloane mutate -> mapping_status='new' (nu aplica orb)."""
|
||||
"""Upload 2 cu coloane mutate -> mapping_status='new' (nu aplica orb)."""
|
||||
# Upload 1 cu header standard
|
||||
data1 = _make_xlsx([_HEADER, _ROW_OK])
|
||||
r1 = _upload_file(client, data1, "test.xlsx")
|
||||
@@ -275,7 +271,7 @@ class TestUploadStaging:
|
||||
assert body["sample_rows"][0]["VIN"] == _ROW_OK2[0]
|
||||
|
||||
def test_purge_after_setat_la_insert(self, client):
|
||||
"""T16: purge_after trebuie setat la insert import_batches."""
|
||||
"""purge_after trebuie setat la insert import_batches."""
|
||||
data = _make_xlsx([_HEADER, _ROW_OK])
|
||||
r = _upload_file(client, data, "test.xlsx")
|
||||
import_id = r.json()["import_id"]
|
||||
@@ -294,7 +290,7 @@ class TestUploadStaging:
|
||||
|
||||
|
||||
# =========================================================================== #
|
||||
# #11 — Mapare coloane (T4) #
|
||||
# Mapare coloane #
|
||||
# =========================================================================== #
|
||||
|
||||
class TestColumnMapping:
|
||||
@@ -349,7 +345,7 @@ class TestColumnMapping:
|
||||
|
||||
|
||||
# =========================================================================== #
|
||||
# #12 — Preview 6 stari (T2 + T11) #
|
||||
# Preview 6 stari #
|
||||
# =========================================================================== #
|
||||
|
||||
class TestPreview:
|
||||
@@ -405,7 +401,7 @@ class TestPreview:
|
||||
assert any(r["resolved_status"] in ("needs_data",) for r in body["rows"])
|
||||
|
||||
def test_preview_already_sent_dupa_submit(self, client):
|
||||
"""Rand deja trimis prin API -> stare already_sent la preview (T2/D5)."""
|
||||
"""Rand deja trimis prin API -> stare already_sent la preview."""
|
||||
# Trimite prin API canalul standard
|
||||
client.post("/v1/prezentari", json={
|
||||
"rar_credentials": {"email": "x@y.ro", "password": "s"},
|
||||
@@ -430,7 +426,7 @@ class TestPreview:
|
||||
assert "already_sent" in statuses, f"Asteptat 'already_sent', primit: {statuses}"
|
||||
|
||||
def test_preview_duplicate_in_file(self, client):
|
||||
"""T11/OV-3: 2 randuri identice in ACELASI fisier -> duplicate_in_file."""
|
||||
"""2 randuri identice in ACELASI fisier -> duplicate_in_file."""
|
||||
# Acelasi rand de doua ori
|
||||
rows = [_HEADER, _ROW_OK, _ROW_OK] # duplicat exact
|
||||
import_id = self._upload_and_map(client, rows=rows)
|
||||
@@ -444,7 +440,7 @@ class TestPreview:
|
||||
f"Asteptat 'duplicate_in_file', primit: {statuses}"
|
||||
|
||||
def test_preview_already_sent_batch_lookup_nu_n_plus_1(self, client):
|
||||
"""Eng#5: already_sent lookup BATCH (nu N+1) — ≤7 interogari pentru 5 randuri."""
|
||||
"""already_sent lookup BATCH (nu N+1) — ≤7 interogari pentru 5 randuri."""
|
||||
# Cream 5 randuri distincte
|
||||
rows_data = [_HEADER]
|
||||
for i in range(5):
|
||||
@@ -492,7 +488,7 @@ class TestPreview:
|
||||
|
||||
|
||||
# =========================================================================== #
|
||||
# #13 — Commit gate HARD + atestare + TOCTOU (T5 + T12) #
|
||||
# Commit gate HARD + atestare + TOCTOU #
|
||||
# =========================================================================== #
|
||||
|
||||
class TestCommit:
|
||||
@@ -528,7 +524,7 @@ class TestCommit:
|
||||
assert body["enqueued"] == n_ok
|
||||
|
||||
def test_commit_cu_n_gresit_reject(self, client):
|
||||
"""T5/D3: commit cu N gresit -> 422, nu enqueue."""
|
||||
"""Commit cu N gresit -> 422, nu enqueue."""
|
||||
import_id, preview = self._upload_preview_ok(client)
|
||||
n_ok = preview["summary"].get("ok", 0)
|
||||
|
||||
@@ -543,7 +539,7 @@ class TestCommit:
|
||||
f"Eroare neasteptata: {detail}"
|
||||
|
||||
def test_commit_log_atestare(self, client):
|
||||
"""T12/Voce#9: commit scrie import_attestations cu rows_hash + n_confirmed."""
|
||||
"""Commit scrie import_attestations cu rows_hash + n_confirmed."""
|
||||
import_id, preview = self._upload_preview_ok(client)
|
||||
n_ok = preview["summary"].get("ok", 0)
|
||||
|
||||
@@ -574,7 +570,7 @@ class TestCommit:
|
||||
conn.close()
|
||||
|
||||
def test_commit_batch_id_setat_pe_submission(self, client):
|
||||
"""T7: submission creata la commit trebuie sa aiba batch_id + row_index setate."""
|
||||
"""Submission creata la commit trebuie sa aiba batch_id + row_index setate."""
|
||||
import_id, preview = self._upload_preview_ok(client)
|
||||
n_ok = preview["summary"].get("ok", 0)
|
||||
|
||||
@@ -602,7 +598,7 @@ class TestCommit:
|
||||
conn.close()
|
||||
|
||||
def test_commit_toctou_cheie_inserata_concurent(self, client):
|
||||
"""Issue 1 (TOCTOU): cheie inserata de canal concurent -> reclasificata already_sent.
|
||||
"""Cheie inserata de canal concurent (TOCTOU) -> reclasificata already_sent.
|
||||
|
||||
Simulam TOCTOU inserand cheia direct in submissions inainte de commit.
|
||||
"""
|
||||
@@ -635,7 +631,6 @@ class TestCommit:
|
||||
"reviewed_rows": [],
|
||||
})
|
||||
# Poate fi 200 cu toctou_collisions sau 422 cu informatii clare
|
||||
# Conform planului Issue 1: reclasificat already_sent, nu rollback
|
||||
# Dar n_enqueued va fi 0 daca toate colideaza
|
||||
if rc.status_code == 200:
|
||||
body = rc.json()
|
||||
@@ -644,7 +639,7 @@ class TestCommit:
|
||||
# (dupa reclasificare, n_total_ok scade)
|
||||
|
||||
def test_commit_needs_review_nebifat_exclus_din_n(self, client):
|
||||
"""Voce#1: rand needs_review nebifat explicit -> NU intra in N, NU se enqueued."""
|
||||
"""Rand needs_review nebifat explicit -> NU intra in N, NU se enqueued."""
|
||||
# Rand cu VIN numeric (coercion -> needs_review)
|
||||
import datetime as dt
|
||||
wb = openpyxl.Workbook()
|
||||
@@ -704,7 +699,7 @@ class TestCommit:
|
||||
assert r2.status_code == 409
|
||||
|
||||
def test_atestare_purge_after_setat_pe_submission(self, client):
|
||||
"""T16: submissions create la commit trebuie sa aiba purge_after setat."""
|
||||
"""Submissions create la commit trebuie sa aiba purge_after setat."""
|
||||
import_id, preview = self._upload_preview_ok(client)
|
||||
n_ok = preview["summary"].get("ok", 0)
|
||||
|
||||
@@ -732,7 +727,7 @@ class TestCommit:
|
||||
|
||||
|
||||
# =========================================================================== #
|
||||
# #14 — Export randuri esuate CSV (T8) #
|
||||
# Export randuri esuate CSV #
|
||||
# =========================================================================== #
|
||||
|
||||
class TestExportFailed:
|
||||
@@ -806,12 +801,12 @@ class TestExportFailed:
|
||||
|
||||
|
||||
# =========================================================================== #
|
||||
# Regresie: reconcile.py ramane op-blind (OV-3) #
|
||||
# Regresie: reconcile.py ramane op-blind #
|
||||
# =========================================================================== #
|
||||
|
||||
class TestReconcileRegresie:
|
||||
def test_match_finalizata_ramane_op_blind(self):
|
||||
"""OV-3: reconcile.py trebuie sa ramana op-blind (nu editat de import).
|
||||
"""reconcile.py trebuie sa ramana op-blind (nu editat de import).
|
||||
|
||||
Importam reconcile si verificam ca nu s-au adaugat parametri de operatie.
|
||||
"""
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"""Teste US-007 (PRD 5.11) — Post-commit: lista Trimiteri apare + refresh auto.
|
||||
"""Teste post-commit: lista Trimiteri apare + refresh auto.
|
||||
|
||||
TDD RED: testele sunt scrise inainte de implementare.
|
||||
Verifica:
|
||||
1. Raspunsul confirma emite header HX-Trigger: trimiteriChanged.
|
||||
2. Raspunsul confirma include OOB swap al #trimiteri-section cu submissions-wrap.
|
||||
@@ -130,7 +129,7 @@ _ROWS_OK = [
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Teste RED → GREEN #
|
||||
# Teste #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
def test_confirma_emite_hx_trigger(client):
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
"""Teste E2E T15 — integrare import->commit->worker (RAR mock) + masina de stari + failure registry.
|
||||
"""Teste E2E: integrare import->commit->worker (RAR mock) + masina de stari + failure registry.
|
||||
|
||||
Acopera (plan T15, sect.12):
|
||||
Acopera:
|
||||
- Scenariul 1: upload xlsx/csv -> column-mapping -> preview -> commit N
|
||||
-> worker process_one (MockRar) -> submission FINALIZATA cu id_prezentare.
|
||||
- Scenariul 2: re-upload acelasi continut -> preview marcheaza already_sent
|
||||
(NU al doilea FINALIZATA dupa commit).
|
||||
- Scenariul 3: coada MIXTA API(creds efemere)+web(creds durabile per-env, US-013):
|
||||
- Scenariul 3: coada mixta API(creds efemere)+web(creds durabile per-env):
|
||||
dupa login + purjare creds efemere, submission-urile web tot se trimit
|
||||
prin fallback accounts.rar_creds_{env}_enc (T1/Voce#5).
|
||||
- Masina de stari (sect. 6): tranzitii queued->sending->sent/requeued/error.
|
||||
- Failure registry (sect. 8): 400/403/503+reconciliere.
|
||||
- T16: purge_expired + purge_after setat la commit.
|
||||
prin fallback accounts.rar_creds_{env}_enc.
|
||||
- Masina de stari: tranzitii queued->sending->sent/requeued/error.
|
||||
- Failure registry: 400/403/503+reconciliere.
|
||||
- Purjare: purge_expired + purge_after setat la commit.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -451,10 +451,10 @@ class TestE2EAlreadySent:
|
||||
|
||||
class TestE2EMixedQueue:
|
||||
def test_coada_mixta_ambele_trimise(self, env, monkeypatch):
|
||||
"""Scenariul 3 (T1/Voce#5): API (creds efemere) + web (canal import, fara creds pe submission).
|
||||
"""Scenariul 3: API (creds efemere) + web (canal import, fara creds pe submission).
|
||||
|
||||
Dupa purjarea creds efemere ale canalului API (la primul login), submission-urile
|
||||
import (web) tot se trimit prin fallback accounts.rar_creds_{env}_enc (US-013, per-env).
|
||||
import (web) tot se trimit prin fallback accounts.rar_creds_{env}_enc, per-env.
|
||||
Verificam ca ambele submission-uri ajung la status='sent'.
|
||||
"""
|
||||
import app.worker.__main__ as w
|
||||
@@ -486,11 +486,11 @@ class TestE2EMixedQueue:
|
||||
assert r_api.status_code == 200, r_api.text
|
||||
sub_api_id = r_api.json()["results"][0]["submission_id"]
|
||||
|
||||
# 3. Seteaza creds durabile in accounts per-env (US-013, canal web fallback)
|
||||
# 3. Seteaza creds durabile in accounts per-env (canal web fallback)
|
||||
conn = get_connection()
|
||||
try:
|
||||
web_creds_enc = encrypt_creds({"email": "web@test.ro", "password": "pass_web"})
|
||||
# US-013: scrie in slotul per-env test (rar_env default = 'test')
|
||||
# scrie in slotul per-env test (rar_env default = 'test')
|
||||
conn.execute(
|
||||
"UPDATE accounts SET rar_creds_test_enc=?, rar_test_enabled=1 WHERE id=1",
|
||||
(web_creds_enc,),
|
||||
@@ -522,7 +522,7 @@ class TestE2EMixedQueue:
|
||||
try:
|
||||
processed = 0
|
||||
|
||||
# Drena coada simuland bucla worker completa (T1/D4: creds efemere + fallback per-env)
|
||||
# Drena coada simuland bucla worker completa: creds efemere + fallback per-env
|
||||
for _ in range(10): # limita de siguranta
|
||||
claimed = w.claim_one(conn)
|
||||
if claimed is None:
|
||||
@@ -532,7 +532,7 @@ class TestE2EMixedQueue:
|
||||
account_id = claimed["account_id"]
|
||||
rar_env = claimed.get("rar_env", "test")
|
||||
|
||||
# T1/D4: creds din submission (API efemer) OR fallback per-env (US-013)
|
||||
# creds din submission (API efemer) OR fallback per-env
|
||||
creds = w._creds_for(claimed, settings) or w._creds_from_account(conn, account_id, rar_env=rar_env)
|
||||
assert creds is not None, \
|
||||
f"Creds None pentru submission {sid} — fallback durabil trebuie sa existe"
|
||||
@@ -566,9 +566,9 @@ class TestE2EMixedQueue:
|
||||
assert mock_rar.post_calls == 2
|
||||
|
||||
def test_purjare_creds_efemere_nu_sterge_durabile(self, env, monkeypatch):
|
||||
"""T1/Gate purjare (OV-5): dupa login, submissions.rar_creds_enc sterse DAR per-env INTACT.
|
||||
"""Dupa login, submissions.rar_creds_enc sterse DAR per-env INTACT.
|
||||
|
||||
Worker sterge DOAR submissions.rar_creds_enc (efemere), NU accounts.rar_creds_{env}_enc (durabile, US-013).
|
||||
Worker sterge DOAR submissions.rar_creds_enc (efemere), NU accounts.rar_creds_{env}_enc (durabile).
|
||||
"""
|
||||
import app.worker.__main__ as w
|
||||
from app.crypto import encrypt_creds
|
||||
@@ -590,7 +590,7 @@ class TestE2EMixedQueue:
|
||||
assert r_api.status_code == 200
|
||||
sub_id = r_api.json()["results"][0]["submission_id"]
|
||||
|
||||
# Seteaza creds durabile pe cont (slotul per-env, US-013)
|
||||
# Seteaza creds durabile pe cont (slotul per-env)
|
||||
conn = get_connection()
|
||||
try:
|
||||
web_creds_enc = encrypt_creds({"email": "web@test.ro", "password": "pass_web"})
|
||||
@@ -634,7 +634,7 @@ class TestE2EMixedQueue:
|
||||
|
||||
|
||||
# =========================================================================== #
|
||||
# Masina de stari (sect. 6 din plan): tranzitii explicite per submission #
|
||||
# Masina de stari: tranzitii explicite per submission #
|
||||
# =========================================================================== #
|
||||
|
||||
class TestStateMachine:
|
||||
@@ -797,7 +797,7 @@ class TestStateMachine:
|
||||
|
||||
|
||||
# =========================================================================== #
|
||||
# Registrul de esecuri (sect. 8): tipuri de eroare RAR si recuperare #
|
||||
# Registrul de esecuri: tipuri de eroare RAR si recuperare #
|
||||
# =========================================================================== #
|
||||
|
||||
class TestFailureRegistry:
|
||||
@@ -929,12 +929,12 @@ class TestFailureRegistry:
|
||||
|
||||
|
||||
# =========================================================================== #
|
||||
# T16 — Purjare (purge_expired + purge_after setat la commit) #
|
||||
# Purjare (purge_expired + purge_after setat la commit) #
|
||||
# =========================================================================== #
|
||||
|
||||
class TestPurjare:
|
||||
def test_purge_expired_sterge_sent_expirate(self, env):
|
||||
"""T16: purge_expired sterge submissions cu status='sent' si purge_after in trecut."""
|
||||
"""purge_expired sterge submissions cu status='sent' si purge_after in trecut."""
|
||||
from app.worker.__main__ import purge_expired
|
||||
|
||||
client, get_connection, get_settings = env
|
||||
@@ -958,7 +958,7 @@ class TestPurjare:
|
||||
conn.close()
|
||||
|
||||
def test_purge_expired_nu_sterge_queued(self, env):
|
||||
"""T16: purge_expired NU sterge non-sent (queued/error) chiar daca purge_after < now."""
|
||||
"""purge_expired NU sterge non-sent (queued/error) chiar daca purge_after < now."""
|
||||
from app.worker.__main__ import purge_expired
|
||||
|
||||
client, get_connection, get_settings = env
|
||||
@@ -981,7 +981,7 @@ class TestPurjare:
|
||||
conn.close()
|
||||
|
||||
def test_purge_after_setat_la_commit_import(self, env):
|
||||
"""T16: submissions create la commit import au purge_after setat (!=NULL)."""
|
||||
"""submissions create la commit import au purge_after setat (!=NULL)."""
|
||||
client, get_connection, get_settings = env
|
||||
|
||||
import_id = _upload_and_map(client, rows=[_HEADER, _ROW_1])
|
||||
@@ -1005,7 +1005,7 @@ class TestPurjare:
|
||||
conn.close()
|
||||
|
||||
def test_purge_after_setat_la_trimitere_worker(self, env):
|
||||
"""T16: dupa trimitere (status='sent'), purge_after se (re)seteaza la now+90 zile."""
|
||||
"""dupa trimitere (status='sent'), purge_after se (re)seteaza la now+90 zile."""
|
||||
import app.worker.__main__ as w
|
||||
|
||||
client, get_connection, get_settings = env
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
"""Teste US-001 (PRD 3.6): backend — persista editarea unui rand de preview.
|
||||
"""Teste backend — persista editarea unui rand de preview.
|
||||
|
||||
Approach B: editarea scrie un patch CANONIC in import_rows.override_json (criptat
|
||||
Editarea scrie un patch CANONIC in import_rows.override_json (criptat
|
||||
Fernet), aplicat ULTIMUL in _resolve_row_for_preview + commit. raw_json/idempotency
|
||||
raman neatinse. Ruta editare = mutatie PURA (nu re-deriva status, nu atinge submissions).
|
||||
|
||||
TDD: testele se scriu inainte de implementare (RED -> GREEN).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-005 (PRD 5.4): erori de import imbracate pe 3 niveluri.
|
||||
"""Teste erori de import imbracate pe 3 niveluri.
|
||||
|
||||
Verifica ca fiecare HTTPException de import in scop are `detail` superset:
|
||||
- cheile vechi: `error`, `message`, context specific (sheets/found/n_ok)
|
||||
@@ -327,7 +327,6 @@ class TestOverrideIlizibil3Niveluri:
|
||||
assert r.status_code == 422, f"Asteptat 422, primit {r.status_code}: {r.text}"
|
||||
detail = r.json()["detail"]
|
||||
|
||||
# Dupa US-005: detail trebuie sa fie dict, nu string
|
||||
assert isinstance(detail, dict), f"detail trebuie sa fie dict, primit: {type(detail)}"
|
||||
assert detail.get("error") == "override_ilizibil"
|
||||
assert detail.get("cod") == "IMPORT_OVERRIDE_ILIZIBIL"
|
||||
|
||||
@@ -143,7 +143,7 @@ def test_preview_arata_panoul_de_mapare(client):
|
||||
assert r.status_code == 200
|
||||
assert "Operatii de mapat la cod RAR" in r.text
|
||||
assert "OP-REV" in r.text
|
||||
# US-004: panoul foloseste ruta plurala (un singur form pentru toate operatiile)
|
||||
# Panoul foloseste ruta plurala (un singur form pentru toate operatiile)
|
||||
assert "/_import/%d/mapare-operatii" % import_id in r.text
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Teste pentru app/import_parse.py (T14 + T3 + T10 + T13).
|
||||
"""Teste pentru app/import_parse.py.
|
||||
|
||||
Fixture-urile xlsx sunt generate in-memory cu openpyxl (nu fisiere binare commituite).
|
||||
Fiecare sectiune acopera un task distinct.
|
||||
Fiecare sectiune acopera un scenariu distinct.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -77,7 +77,7 @@ _ROW2 = ["WVWZZZ1KZAW000124", "CJ001AB", "2026-05-10", "98765", "Reparatie"]
|
||||
|
||||
|
||||
# =========================================================================== #
|
||||
# T14 — CSV delimiter sniff + encoding + cap #
|
||||
# CSV delimiter sniff + encoding + cap #
|
||||
# =========================================================================== #
|
||||
|
||||
class TestCsvDelimiter:
|
||||
@@ -134,7 +134,7 @@ class TestCsvDelimiter:
|
||||
|
||||
|
||||
# =========================================================================== #
|
||||
# T14 — XLSX read_only dim-check + cap #
|
||||
# XLSX read_only dim-check + cap #
|
||||
# =========================================================================== #
|
||||
|
||||
class TestXlsxDimcheck:
|
||||
@@ -176,7 +176,7 @@ class TestXlsxDimcheck:
|
||||
|
||||
|
||||
# =========================================================================== #
|
||||
# T3 — coercion guard + needs_review + mesaj formule-None #
|
||||
# Coercion guard + needs_review + mesaj formule-None #
|
||||
# =========================================================================== #
|
||||
|
||||
class TestCoercionNeedsReview:
|
||||
@@ -278,7 +278,7 @@ class TestCoercionNeedsReview:
|
||||
|
||||
|
||||
# =========================================================================== #
|
||||
# T10 — dezambiguizare data la nivel de COLOANA (OV-8) #
|
||||
# Dezambiguizare data la nivel de coloana #
|
||||
# =========================================================================== #
|
||||
|
||||
class TestDateColumnDisambiguation:
|
||||
@@ -344,7 +344,7 @@ class TestDateColumnDisambiguation:
|
||||
|
||||
|
||||
# =========================================================================== #
|
||||
# T13 — robustete export RO (multi-sheet + merged header + footer trim) #
|
||||
# Robustete export RO (multi-sheet + merged header + footer trim) #
|
||||
# =========================================================================== #
|
||||
|
||||
class TestRobustetExportRO:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-009 (PRD 5.20) — Import web: selector mediu RAR conditionat de disponibilitate.
|
||||
"""Teste import web: selector mediu RAR conditionat de disponibilitate.
|
||||
|
||||
Verifica:
|
||||
- La 0 medii: banner avertisment non-blocant (upload functioneaza, commit foloseste ancora globala).
|
||||
@@ -326,7 +326,7 @@ def test_commit_cu_doua_medii_respecta_alegerea(client):
|
||||
|
||||
|
||||
def test_badge_mediu_in_preview(client):
|
||||
"""Preview-ul afiseaza badge-ul cu mediul tinta (US-009, F9/F10)."""
|
||||
"""Preview-ul afiseaza badge-ul cu mediul tinta."""
|
||||
_seed_nomenclator_si_mapare(client)
|
||||
_configureaza_un_mediu(client, env="test")
|
||||
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
"""Teste US-007 (PRD 5.12): gate review in modal — import_rows.reviewed + confirmare.
|
||||
|
||||
TDD RED: testele sunt scrise inainte de implementare.
|
||||
"""Gate review in modal — import_rows.reviewed + confirmare.
|
||||
|
||||
Scenarii:
|
||||
1. Migrare: import_rows.reviewed INTEGER DEFAULT 0, idempotent.
|
||||
2. Rand needs_review exclus din "gata de trimis" pana la confirmare explicita.
|
||||
3. POST confirma-review seteaza reviewed=1 → randul devine ok la recalcul.
|
||||
4. `reviewed` NU intra in payload/idempotency (marcaj separat).
|
||||
5. Editarea unei valori pe un rand confirmat reseteaza reviewed=0 (D#9).
|
||||
5. Editarea unei valori pe un rand confirmat reseteaza reviewed=0.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -268,8 +266,8 @@ def test_migrare_adauga_coloana_reviewed_idempotent():
|
||||
def test_needs_review_exclus_din_gata_pana_la_confirmare(client):
|
||||
"""Un rand needs_review nu intra in 'gata de trimis' (n_confirmat = 0) pana la confirmare.
|
||||
|
||||
US-007 Q1: randul cu data ambigua apare cu pill 'Verifica valori' si este
|
||||
EXCLUS din n_confirmat. Bannerul de discoverability (T1) trebuie sa fie prezent.
|
||||
Randul cu data ambigua apare cu pill 'Verifica valori' si este
|
||||
EXCLUS din n_confirmat. Bannerul de discoverability trebuie sa fie prezent.
|
||||
"""
|
||||
_seed_op1()
|
||||
iid = _upload_and_preview_needs_review(client)
|
||||
@@ -295,7 +293,7 @@ def test_needs_review_exclus_din_gata_pana_la_confirmare(client):
|
||||
assert n_val == 0, \
|
||||
f"n_confirmat trebuie sa fie 0 cand randul e needs_review (negasit), got {n_val}"
|
||||
|
||||
# Bannerul de discoverability (T1) — prezent cand summary.needs_review > 0
|
||||
# Bannerul de discoverability — prezent cand summary.needs_review > 0
|
||||
# Trebuie sa contina un mesaj despre faptul ca randurile nu pleaca pana la confirmare
|
||||
# (ex. 'nu pleaca la RAR' sau 'confirmi in modal' sau 'Verifica valori')
|
||||
banner_present = (
|
||||
@@ -304,13 +302,13 @@ def test_needs_review_exclus_din_gata_pana_la_confirmare(client):
|
||||
"preview-needs-review-banner" in html
|
||||
)
|
||||
assert banner_present, \
|
||||
"Bannerul de discoverability (T1) trebuie sa fie prezent cand exista randuri needs_review"
|
||||
"Bannerul de discoverability trebuie sa fie prezent cand exista randuri needs_review"
|
||||
|
||||
|
||||
def test_confirmare_in_modal_seteaza_reviewed_si_devine_ok(client):
|
||||
"""POST /_import/{id}/rand/0/confirma-review seteaza reviewed=1.
|
||||
|
||||
US-007 T2: operatorul apasa 'Confirma valorile' in modal →
|
||||
Operatorul apasa 'Confirma valorile' in modal →
|
||||
reviewed=1 in DB → randul devine ok la recalcul preview.
|
||||
|
||||
Verifica:
|
||||
@@ -350,9 +348,8 @@ def test_confirmare_in_modal_seteaza_reviewed_si_devine_ok(client):
|
||||
def test_reviewed_nu_intra_in_payload_sau_idempotency(client):
|
||||
"""reviewed NU intra in payload, override_json sau cheia de idempotenta.
|
||||
|
||||
US-007 marcaj separat (D#8): reviewed e DOAR un flag de confirmare umana,
|
||||
nu un camp de continut. Cheia de idempotenta trebuie sa fie identica inainte
|
||||
si dupa confirmare.
|
||||
reviewed e DOAR un flag de confirmare umana, nu un camp de continut.
|
||||
Cheia de idempotenta trebuie sa fie identica inainte si dupa confirmare.
|
||||
"""
|
||||
_seed_op1()
|
||||
iid = _upload_and_preview_needs_review(client)
|
||||
@@ -393,7 +390,7 @@ def test_reviewed_nu_intra_in_payload_sau_idempotency(client):
|
||||
|
||||
|
||||
def test_editare_valoare_pe_needs_review_reseteaza_reviewed(client):
|
||||
"""Editarea unei valori pe un rand confirmat reseteaza reviewed=0 (D#9).
|
||||
"""Editarea unei valori pe un rand confirmat reseteaza reviewed=0.
|
||||
|
||||
Cand operatorul SCHIMBA o valoare (via POST editeaza) pe un rand deja confirmat
|
||||
(reviewed=1), apply_row_override trebuie sa reseteze reviewed=0.
|
||||
@@ -418,7 +415,7 @@ def test_editare_valoare_pe_needs_review_reseteaza_reviewed(client):
|
||||
|
||||
# reviewed trebuie sa fie 0 (resetat de apply_row_override)
|
||||
assert _get_reviewed(iid, 0) == 0, \
|
||||
"reviewed trebuie sa fie resetat la 0 dupa editarea unei valori (D#9 — re-cere confirmare)"
|
||||
"reviewed trebuie sa fie resetat la 0 dupa editarea unei valori (re-cere confirmare)"
|
||||
|
||||
|
||||
def test_confirma_review_guard_committed_409(client):
|
||||
@@ -544,11 +541,11 @@ def test_confirma_review_scoped_404_alt_cont():
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Teste markup Bug 1: confirma-review form swap (B1) #
|
||||
# Teste markup: confirma-review form swap #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
def test_confirma_review_form_nu_foloseste_hx_swap_none():
|
||||
"""Bug B1 (markup): formularul confirma-review NU trebuie sa foloseasca
|
||||
"""Formularul confirma-review NU trebuie sa foloseasca
|
||||
hx-swap='none' — cu none, htmx aplica doar OOB-urile dar NU executa scriptul
|
||||
din continutul principal → updateN() nu ruleaza → n_confirmat stale → 422.
|
||||
|
||||
@@ -561,7 +558,7 @@ def test_confirma_review_form_nu_foloseste_hx_swap_none():
|
||||
)
|
||||
html = template.read_text(encoding="utf-8")
|
||||
|
||||
# Gasim sectiunea formularului confirma-review (dupa marcajul T2)
|
||||
# Gasim sectiunea formularului confirma-review
|
||||
idx = html.find("confirma-review")
|
||||
assert idx >= 0, "Formularul confirma-review nu a fost gasit in template"
|
||||
form_section = html[idx:]
|
||||
@@ -622,7 +619,7 @@ _ROWS_MULTI_NEEDS_REVIEW = [
|
||||
|
||||
|
||||
def test_confirma_toate_review_marcheaza_toate(client):
|
||||
"""B1 bulk: POST /_import/{id}/confirma-toate-review seteaza reviewed=1 pe TOATE
|
||||
"""POST /_import/{id}/confirma-toate-review seteaza reviewed=1 pe TOATE
|
||||
randurile needs_review din batch cu un singur click.
|
||||
|
||||
Verifica:
|
||||
@@ -776,7 +773,7 @@ def test_confirma_toate_review_scoped_404_alt_cont():
|
||||
|
||||
|
||||
def test_confirm_rapid_buton_prezent_in_tabel(client):
|
||||
"""B1 quick: randul needs_review are butonul de confirm rapid direct in tabel,
|
||||
"""Randul needs_review are butonul de confirm rapid direct in tabel,
|
||||
care POST-eaza pe ruta /confirma-review (fara a deschide modalul)."""
|
||||
_seed_op1()
|
||||
iid = _upload_and_preview_needs_review(client)
|
||||
@@ -791,7 +788,7 @@ def test_confirm_rapid_buton_prezent_in_tabel(client):
|
||||
|
||||
|
||||
def test_confirm_rapid_per_rand_seteaza_reviewed(client):
|
||||
"""B1 quick: POST /confirma-review din tabel (fara modal) seteaza reviewed=1 pe un
|
||||
"""POST /confirma-review din tabel (fara modal) seteaza reviewed=1 pe un
|
||||
singur rand si NU atinge celelalte randuri needs_review din batch."""
|
||||
_seed_op1()
|
||||
iid = _upload_and_preview_rows(client, _ROWS_MULTI_NEEDS_REVIEW)
|
||||
@@ -806,7 +803,7 @@ def test_confirm_rapid_per_rand_seteaza_reviewed(client):
|
||||
|
||||
|
||||
def test_confirma_review_cere_reincarcarea_preview(client):
|
||||
"""Contractul nou (dogfood 5.13): confirma-review NU mai depinde de scriptul updateN
|
||||
"""Confirma-review NU mai depinde de scriptul updateN
|
||||
din payload (care, cu OOB pe <tr> rupt, lasa randul stale). Acum cere reincarcaPreview,
|
||||
iar preview-ul reincarcat re-randeaza contorul si butonul de confirmare cu n_confirmat
|
||||
corect server-side — deci problema B1 (n_confirmat stale -> 422) dispare structural.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste UI web import (U5) — upload → mapare coloane → preview → confirmare.
|
||||
"""Teste UI web import — upload → mapare coloane → preview → confirmare.
|
||||
|
||||
Verifica:
|
||||
- Dashboard randeaza sectiunea de upload
|
||||
@@ -104,7 +104,7 @@ def _seed_op_mapping(client, cod_op: str = "Revizie", cod_prest: str = "OE-1") -
|
||||
def test_dashboard_contine_drop_zone(client):
|
||||
"""Tab-ul Import randeaza sectiunea de upload cu drop zone si mesaj warmth.
|
||||
|
||||
Dupa US-003 sectiunea de import e in tab-ul Import (?tab=import), nu pe pagina principala.
|
||||
Sectiunea de import e in tab-ul Import (?tab=import), nu pe pagina principala.
|
||||
"""
|
||||
r = client.get("/?tab=import")
|
||||
assert r.status_code == 200
|
||||
@@ -389,11 +389,11 @@ def test_upload_multi_sheet_arata_selector(client):
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Elemente a11y (D10/D11/D12) #
|
||||
# Elemente a11y #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
def test_preview_contine_banner_declarant(client):
|
||||
"""Preview contine bannerul declarant (D12) cu text despre ireversibil."""
|
||||
"""Preview contine bannerul declarant cu text despre ireversibil."""
|
||||
import_id = _setup_preview(client)
|
||||
r = client.get(f"/_import/{import_id}/preview")
|
||||
assert r.status_code == 200
|
||||
@@ -403,7 +403,7 @@ def test_preview_contine_banner_declarant(client):
|
||||
|
||||
|
||||
def test_preview_contine_checkboxuri_needs_review(client):
|
||||
"""Randurile needs_review au checkbox 'verificat' (D11)."""
|
||||
"""Randurile needs_review au checkbox 'verificat'."""
|
||||
# Cream un rand cu VIN numeric → needs_review
|
||||
rows_with_review = [
|
||||
{
|
||||
@@ -431,7 +431,7 @@ def test_preview_contine_checkboxuri_needs_review(client):
|
||||
|
||||
|
||||
def test_preview_duplicate_in_file_are_text(client):
|
||||
"""Randurile duplicate_in_file arata text 'dubla cu randul N' (D10 — nu doar culoare)."""
|
||||
"""Randurile duplicate_in_file arata text 'dubla cu randul N' (nu doar culoare)."""
|
||||
_seed_op_mapping(client, "Revizie", "OE-1")
|
||||
# Doua randuri identice → duplicate_in_file
|
||||
dup_rows = [
|
||||
@@ -451,6 +451,6 @@ def test_preview_duplicate_in_file_are_text(client):
|
||||
)
|
||||
r = client.get(f"/_import/{import_id}/preview")
|
||||
assert r.status_code == 200
|
||||
# Text explicit pentru duplicate_in_file (nu doar culoare — cerinta daltonism D10)
|
||||
# Text explicit pentru duplicate_in_file (nu doar culoare — cerinta daltonism)
|
||||
assert "dubla cu randul" in r.text
|
||||
assert "duplicate_in_file" in r.text
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"""Teste US-006a/b (PRD 3.3): scoping import web pe sesiune.
|
||||
"""Scoping import web pe sesiune.
|
||||
|
||||
US-006a: citiri (upload, preview, mapare-coloane) pe contul sesiunii.
|
||||
US-006b: scrieri (confirma) pe contul sesiunii; alt cont -> inaccesibil.
|
||||
C8/OV-2: aceeasi cheie idempotenta prin API si web pe acelasi cont.
|
||||
Citiri (upload, preview, mapare-coloane) pe contul sesiunii.
|
||||
Scrieri (confirma) pe contul sesiunii; alt cont -> inaccesibil.
|
||||
Aceeasi cheie idempotenta prin API si web pe acelasi cont.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -144,7 +144,7 @@ def test_commit_creeaza_submissions_pe_cont(env, monkeypatch):
|
||||
|
||||
|
||||
def test_cheie_identica_api_vs_web_acelasi_cont(env, monkeypatch):
|
||||
"""C8/OV-2: import web si API pe acelasi cont produc aceeasi cheie idempotenta."""
|
||||
"""Import web si API pe acelasi cont produc aceeasi cheie idempotenta."""
|
||||
from app.idempotency import build_key, canonicalize_row
|
||||
client, conn, acct_a, acct_b = env
|
||||
_setup_op_mapping(conn, acct_a)
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
"""Teste US-001: endpoint-uri de integrare (GET /v1/ping + export Postman).
|
||||
|
||||
TDD — toate testele RED inainte de implementare.
|
||||
"""
|
||||
"""Teste endpoint-uri de integrare (GET /v1/ping + export Postman)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -64,13 +61,13 @@ def _creeaza_cheie(monkeypatch) -> str:
|
||||
|
||||
|
||||
def _seteaza_rar_creds(monkeypatch=None) -> None:
|
||||
"""Seteaza creds RAR pe contul id=1 (slotul per-env, US-013)."""
|
||||
"""Seteaza creds RAR pe contul id=1 (slotul per-env)."""
|
||||
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"})
|
||||
# US-013: scrie in slotul per-env (test = ancora globala in teste)
|
||||
# Scrie in slotul per-env (test = ancora globala in teste)
|
||||
conn.execute(
|
||||
"UPDATE accounts SET rar_creds_test_enc=?, rar_test_enabled=1 WHERE id=1", (enc,)
|
||||
)
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
"""Teste US-004: POST /integrare/test-cheie — verifica cheia API lipita de utilizator.
|
||||
|
||||
TDD: testele se scriu INAINTE de implementare; la inceput pica (RED),
|
||||
dupa implementare trec (GREEN).
|
||||
|
||||
Ruta testata:
|
||||
- POST /integrare/test-cheie -> fragment HTML cu rezultat validare
|
||||
"""
|
||||
"""Teste POST /integrare/test-cheie — verifica cheia API lipita de utilizator."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-007 (PRD 5.6): gard de redactare PII/parole in jurnal (L.142/GDPR)."""
|
||||
"""Gard de redactare PII/parole in jurnal (L.142/GDPR)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-008 (PRD 5.6): retentie / purjare jurnal + RotatingFileHandler."""
|
||||
"""Teste retentie / purjare jurnal + RotatingFileHandler."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,19 +1,10 @@
|
||||
"""
|
||||
Teste pentru eticheta_scurta (US-006, PRD 5.8).
|
||||
|
||||
RED intai: scrise inainte de implementarea functiei.
|
||||
Fisiere atinse: app/web/labels.py, tests/test_labels.py.
|
||||
"""
|
||||
"""Teste pentru eticheta_scurta."""
|
||||
|
||||
import pytest
|
||||
|
||||
from app.web.labels import eticheta_scurta, eticheta_stare
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# test_eticheta_scurta_pentru_fiecare_stare
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_eticheta_scurta_pentru_fiecare_stare():
|
||||
"""Fiecare stare cunoscuta intoarce eticheta scurta corecta (pill)."""
|
||||
cazuri = {
|
||||
@@ -37,13 +28,8 @@ def test_eticheta_scurta_stare_necunoscuta_ridica_keyerror():
|
||||
eticheta_scurta("stare_inexistenta")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# test_eticheta_lunga_ramane_pentru_subtext
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_eticheta_lunga_ramane_pentru_subtext():
|
||||
"""eticheta_stare inca intoarce textele lungi neschimbate (compat cu template-uri)."""
|
||||
# Verificam fragmentele de text lung care existau inainte de US-006
|
||||
cazuri_lungi = {
|
||||
"queued": "In asteptare",
|
||||
"sending": "Se trimite acum",
|
||||
@@ -57,7 +43,6 @@ def test_eticheta_lunga_ramane_pentru_subtext():
|
||||
assert fragment.lower() in text.lower(), (
|
||||
f"eticheta_stare({status!r}) text lung modificat — asteptam {fragment!r} in {text!r}"
|
||||
)
|
||||
# Verifica ca tuple-ul are exact 3 elemente (invariant arhitectura C1)
|
||||
assert isinstance(css_class, str) and css_class, (
|
||||
f"eticheta_stare({status!r}) trebuie sa aiba css_class non-vida la pozitia 3"
|
||||
)
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
"""
|
||||
Teste pentru eticheta randurilor tinute manual (held) — US-006, PRD 5.19.
|
||||
Teste pentru eticheta randurilor tinute manual (held).
|
||||
|
||||
RED intai: scrise inainte de a extinde labels.py cu parametrul `held`.
|
||||
|
||||
Regula de afisaj (D5, PRD 5.19):
|
||||
Regula de afisaj:
|
||||
- `status='queued' AND held=1` -> "In asteptare (manual)" + clasa CSS de
|
||||
AVERTIZARE (amber, `--warn`) — asteptare benigna, NU eroare (rosu).
|
||||
- `held=0` (sau lipsa) -> comportament neschimbat pentru TOATE starile.
|
||||
- `held` NU e stare noua in masina de stari: CHECK-ul din schema ramane neatins.
|
||||
|
||||
Fisiere atinse: app/web/labels.py, tests/test_labels_held.py.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
@@ -44,7 +40,7 @@ def test_queued_held_are_eticheta_manuala_si_clasa_warn():
|
||||
|
||||
|
||||
def test_queued_held_false_ramane_neschimbat():
|
||||
"""queued fara held == comportamentul dinainte de US-006 (PRD 5.19)."""
|
||||
"""queued fara held == comportamentul dinainte de introducerea held."""
|
||||
fara_held = eticheta_stare("queued")
|
||||
held_false = eticheta_stare("queued", held=False)
|
||||
assert fara_held == held_false, "held=False trebuie identic cu apelul fara held"
|
||||
@@ -67,14 +63,14 @@ def test_apel_pozitional_compat():
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# eticheta_scurta (pill) — pill-ul trebuie sa distinga held de queued normal (D5)
|
||||
# eticheta_scurta (pill) — pill-ul trebuie sa distinga held de queued normal
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_pill_queued_held_diferit_de_queued_normal():
|
||||
pill_held = eticheta_scurta("queued", held=True)
|
||||
pill_normal = eticheta_scurta("queued", held=False)
|
||||
assert pill_held != pill_normal, (
|
||||
"pill-ul trebuie sa distinga randul tinut (D5: altfel randa 'In coada' identic)"
|
||||
"pill-ul trebuie sa distinga randul tinut (altfel randa 'In coada' identic)"
|
||||
)
|
||||
assert pill_normal == "In coada"
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
"""TDD L14-S6 — Integrare Layer 2/3 in editor (suggestion-only, DUPA 5.15).
|
||||
"""Integrare sugestii de mapare in editor (suggestion-only).
|
||||
|
||||
Scenarii acoperite:
|
||||
- F1-regression CRITIC: SILVER/shared GOLD NU auto-trimit (resolve_prestatii neschimbat)
|
||||
- pending_unmapped include sugestie GOLD partajat > SILVER > embeddings (precedenta Eng-F2)
|
||||
- SILVER/shared GOLD NU auto-trimit (resolve_prestatii neschimbat)
|
||||
- pending_unmapped include sugestie GOLD partajat > SILVER > embeddings
|
||||
- record_human_validation apelat la confirmare umana (POST /mapari -> shared_mappings)
|
||||
- Degradare gratioasa cand embeddings indisponibil (mock is_available=False)
|
||||
- Separare structurala #13: resolve_prestatii/load_mapping NU citesc tabelele de sugestii
|
||||
- Separare structurala: resolve_prestatii/load_mapping NU citesc tabelele de sugestii
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -62,11 +62,11 @@ def client(env):
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# F1-regression CRITIC: SILVER/shared GOLD NU auto-trimit #
|
||||
# Regresie critica: SILVER/shared GOLD NU auto-trimit #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
def test_f1_silver_nu_auto_trimite(conn):
|
||||
"""CRITICAL F1: un cod in SILVER (mapping_suggestions) NU produce auto-trimitere.
|
||||
"""Un cod in SILVER (mapping_suggestions) NU produce auto-trimitere.
|
||||
|
||||
resolve_prestatii cu mapping gol + SILVER existent -> operatie ramane nemapata.
|
||||
Submissionul ar ramane needs_mapping, NU queued.
|
||||
@@ -84,13 +84,13 @@ def test_f1_silver_nu_auto_trimite(conn):
|
||||
[{"cod_op_service": "OP-REV", "denumire": "Revizie periodica"}],
|
||||
{}, # operations_mapping gol
|
||||
)
|
||||
# Operatia ramane nemapata (SILVER nu e in resolve, #13)
|
||||
# Operatia ramane nemapata (SILVER nu e in resolve)
|
||||
assert resolved[0]["cod_prestatie"] is None
|
||||
assert len(unmapped) == 1
|
||||
|
||||
|
||||
def test_f1_shared_gold_nu_auto_trimite(conn):
|
||||
"""CRITICAL F1: un cod in shared_mappings (GOLD partajat) NU produce auto-trimitere.
|
||||
"""Un cod in shared_mappings (GOLD partajat) NU produce auto-trimitere.
|
||||
|
||||
resolve_prestatii cu mapping gol + shared GOLD existent -> operatie ramane nemapata.
|
||||
"""
|
||||
@@ -105,13 +105,13 @@ def test_f1_shared_gold_nu_auto_trimite(conn):
|
||||
[{"cod_op_service": "OP-ULEI", "denumire": "Schimb ulei motor"}],
|
||||
{}, # operations_mapping gol
|
||||
)
|
||||
# Operatia ramane nemapata (GOLD partajat nu e in resolve, #13)
|
||||
# Operatia ramane nemapata (GOLD partajat nu e in resolve)
|
||||
assert resolved[0]["cod_prestatie"] is None
|
||||
assert len(unmapped) == 1
|
||||
|
||||
|
||||
def test_f1_load_mapping_nu_citeste_shared_gold(conn):
|
||||
"""Separare #13: load_mapping NU returneaza coduri din shared_mappings."""
|
||||
"""load_mapping NU returneaza coduri din shared_mappings."""
|
||||
from app.shared_store import record_human_validation
|
||||
from app.mapping import load_mapping
|
||||
|
||||
@@ -175,7 +175,7 @@ def test_enrich_include_silver(conn):
|
||||
|
||||
|
||||
def test_enrich_precedenta_gold_peste_silver(conn):
|
||||
"""Precedenta Eng-F2: GOLD partajat castiga fata de SILVER cand ambele exista."""
|
||||
"""GOLD partajat castiga fata de SILVER cand ambele exista."""
|
||||
from app.shared_store import seed_suggestions, record_human_validation
|
||||
from app.mapping import enrich_suggestions
|
||||
|
||||
@@ -197,7 +197,7 @@ def test_enrich_precedenta_gold_peste_silver(conn):
|
||||
|
||||
|
||||
def test_enrich_degradare_embeddings_indisponibil(conn, monkeypatch):
|
||||
"""Degradare gratioasa (#16b): cand embeddings nu e disponibil, nu eroare."""
|
||||
"""Degradare gratioasa: cand embeddings nu e disponibil, nu eroare."""
|
||||
import app.embeddings as emb_mod
|
||||
monkeypatch.setattr(emb_mod, "is_available", lambda: False)
|
||||
|
||||
@@ -210,7 +210,7 @@ def test_enrich_degradare_embeddings_indisponibil(conn, monkeypatch):
|
||||
|
||||
|
||||
def test_enrich_corpus_gol_nu_incarca_modelul(conn, monkeypatch):
|
||||
"""Bug fix (code-review): enrich_suggestions NU lazy-load-eaza modelul de 220MB
|
||||
"""enrich_suggestions NU lazy-load-eaza modelul de 220MB
|
||||
cand corpus-ul embeddings e gol.
|
||||
|
||||
Implementarea veche apela `is_available()` neconditionat -> `_get_engine()` ->
|
||||
@@ -258,7 +258,7 @@ class _FakeEmbedBackend:
|
||||
|
||||
|
||||
def test_embeddings_functional_cand_flag_activ(conn, monkeypatch):
|
||||
"""PRD #15: cu AUTOPASS_EMBEDDINGS_ENABLED=true, embeddings produce efectiv o sugestie.
|
||||
"""Cu AUTOPASS_EMBEDDINGS_ENABLED=true, embeddings produce efectiv o sugestie.
|
||||
|
||||
Wire-uieste ensure_embeddings_corpus (corpus din nomenclator) + enrich_suggestions.
|
||||
Backend injectat (determinist) -> nu incarca modelul real de 230MB.
|
||||
@@ -272,7 +272,7 @@ def test_embeddings_functional_cand_flag_activ(conn, monkeypatch):
|
||||
get_settings.cache_clear()
|
||||
monkeypatch.setattr(emb_mod, "_engine", EmbeddingEngine(backend=_FakeEmbedBackend()))
|
||||
|
||||
# Corpusul sursa = mapping_suggestions (SILVER) -- PRD 5.18 US-005.
|
||||
# Corpusul sursa = mapping_suggestions (SILVER).
|
||||
# (Inainte era nomenclator_rar; migrat la mapping_suggestions ca k-NN sa
|
||||
# opereze pe exemple reale etichetate, nu pe categorii generice RAR.)
|
||||
conn.execute(
|
||||
@@ -362,7 +362,7 @@ def test_pending_unmapped_include_sugestie_principala(conn):
|
||||
assert len(pending) == 1
|
||||
entry = pending[0]
|
||||
|
||||
# sugestie_principala adaugat de enrich_suggestions (L14-S6)
|
||||
# sugestie_principala adaugat de enrich_suggestions
|
||||
assert "sugestie_principala" in entry
|
||||
sp = entry["sugestie_principala"]
|
||||
assert sp is not None
|
||||
@@ -434,7 +434,7 @@ def test_record_human_validation_la_post_mapari(env, client):
|
||||
finally:
|
||||
conn_setup.close()
|
||||
|
||||
# POST /mapari cu denumire (L14-S6: form include denumire hidden)
|
||||
# POST /mapari cu denumire (form include denumire hidden)
|
||||
resp = client.post(
|
||||
"/mapari",
|
||||
data={
|
||||
@@ -511,7 +511,7 @@ def test_record_human_validation_la_mapeaza_inline(env, client):
|
||||
|
||||
|
||||
def test_mapare_salvata_fara_denumire_nu_polueaza_gold(env, client):
|
||||
"""Bug fix (code-review 5.15): editarea unei mapari salvate FARA denumire NU scrie
|
||||
"""Editarea unei mapari salvate FARA denumire NU scrie
|
||||
o intrare bogus in GOLD partajat (cheiata pe cod_op_service in loc de denumire umana).
|
||||
|
||||
Formularul din _mapari.html nu trimite denumire; vechiul fallback `denumire or
|
||||
@@ -554,11 +554,11 @@ def test_mapare_salvata_fara_denumire_nu_polueaza_gold(env, client):
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Separare structurala #13 (redundant cu test_shared_store dar explicit L14) #
|
||||
# Separare structurala (redundant cu test_shared_store dar explicit) #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
def test_separare_silver_din_resolve_prestatii():
|
||||
"""#13: resolve_prestatii nu citeste mapping_suggestions (SILVER)."""
|
||||
"""resolve_prestatii nu citeste mapping_suggestions (SILVER)."""
|
||||
from app.mapping import resolve_prestatii
|
||||
|
||||
# Apelam fara conn (pur) — SILVER nu e parametru si nu e accesat
|
||||
@@ -571,7 +571,7 @@ def test_separare_silver_din_resolve_prestatii():
|
||||
|
||||
|
||||
def test_separare_shared_gold_din_resolve_prestatii():
|
||||
"""#13: resolve_prestatii nu citeste shared_mappings (GOLD partajat)."""
|
||||
"""resolve_prestatii nu citeste shared_mappings (GOLD partajat)."""
|
||||
from app.mapping import resolve_prestatii
|
||||
|
||||
resolved, unmapped = resolve_prestatii(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Teste US-005 (PRD 3.6): "De rezolvat" si "Operatii salvate" randate ca TABELE.
|
||||
"""Teste: "De rezolvat" si "Operatii salvate" randate ca TABELE.
|
||||
|
||||
Doar marcaj de template — POST-urile /mapari, /mapari/salvate, /mapari/salvate/sterge
|
||||
raman identice. H4: comutatorul auto-send din tabelul salvate reflecta valoarea STOCATA
|
||||
raman identice. Comutatorul auto-send din tabelul salvate reflecta valoarea STOCATA
|
||||
per mapare (din _load_saved_op_mappings), nu un default hard.
|
||||
"""
|
||||
|
||||
@@ -150,7 +150,7 @@ def test_mapari_de_rezolvat_in_tabel(client):
|
||||
|
||||
|
||||
def test_mapari_salvate_in_tabel(client):
|
||||
"""Sectiunea "Operatii salvate" randata ca tabel. US-002: fara coloana auto_send."""
|
||||
"""Sectiunea "Operatii salvate" randata ca tabel, fara coloana auto_send."""
|
||||
acct = _create_account_user("salv@test.com")
|
||||
_seed_nomenclator("R-FRANE", "Reparatie frane")
|
||||
_seed_nomenclator("R-MOTOR", "Reparatie motor")
|
||||
@@ -165,9 +165,9 @@ def test_mapari_salvate_in_tabel(client):
|
||||
assert "tablewrap" in sec, "tabelul Operatii salvate trebuie sa foloseasca .tablewrap"
|
||||
assert "<table" in sec and "<th" in sec, "Operatii salvate trebuie randat ca tabel cu antet"
|
||||
assert "OP-AUTO" in sec and "OP-MANUAL" in sec
|
||||
# US-002: checkbox auto_send si coloana In coada scoase din UI
|
||||
assert 'name="auto_send"' not in sec, "US-002: checkbox auto_send scos din tabelul salvate"
|
||||
assert "In coada" not in sec, "US-002: coloana In coada scoasa din tabelul salvate"
|
||||
# checkbox auto_send si coloana In coada scoase din UI
|
||||
assert 'name="auto_send"' not in sec, "checkbox auto_send scos din tabelul salvate"
|
||||
assert "In coada" not in sec, "coloana In coada scoasa din tabelul salvate"
|
||||
# POST-urile neschimbate
|
||||
assert 'hx-post="/mapari/salvate"' in sec
|
||||
assert 'hx-post="/mapari/salvate/sterge"' in sec
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Teste mapare op ROAAUTO -> cod RAR: fuzzy, rezolvare pura, flux on-demand.
|
||||
|
||||
Contract hibrid (decis 2026-06-15): item de prestatie cu cod_prestatie (RAR direct)
|
||||
SAU cod_op_service+denumire (mapat de gateway). Op nemapata -> needs_mapping, apare
|
||||
Contract hibrid: item de prestatie cu cod_prestatie (RAR direct) SAU
|
||||
cod_op_service+denumire (mapat de gateway). Op nemapata -> needs_mapping, apare
|
||||
in editor; la salvarea maparii submission-ul se re-rezolva automat.
|
||||
"""
|
||||
|
||||
@@ -109,7 +109,7 @@ def test_resolve_fara_valid_codes_e_backcompat():
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# US-002: reguli text (substring) dupa maparea exacta #
|
||||
# reguli text (substring) dupa maparea exacta #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
def test_regula_text_contains_rezolva():
|
||||
@@ -313,7 +313,7 @@ def test_on_unmapped_error_respinge_fara_enqueue(client):
|
||||
assert res["status"] == "error"
|
||||
assert res["submission_id"] is None
|
||||
assert res["erori"] and res["erori"][0]["cod"] == "COD_NEMAPAT"
|
||||
# PRD 5.7: raspuns onest si pe ramura respinsa — nemapate + motiv populate (aditiv).
|
||||
# raspuns onest si pe ramura respinsa — nemapate + motiv populate (aditiv).
|
||||
assert res["nemapate"] and res["nemapate"][0]["cod_op_service"] == _COD_INTERN
|
||||
assert res["motiv"]
|
||||
# Nu s-a creat nimic in coada.
|
||||
@@ -348,7 +348,7 @@ def test_valideaza_error_mode(client):
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# US-003: 3 niveluri in classify_prezentare (needs_mapping) #
|
||||
# 3 niveluri in classify_prezentare (needs_mapping) #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
def test_unmapped_are_3niveluri(client):
|
||||
@@ -381,9 +381,9 @@ def test_unmapped_are_3niveluri(client):
|
||||
|
||||
|
||||
def test_auto_send_oprit_3niveluri_noul_comportament(client):
|
||||
"""Mapare cu auto_send=0 -> queued (auto_send ignorat dupa US-001).
|
||||
"""Mapare cu auto_send=0 -> queued (auto_send ignorat).
|
||||
|
||||
Dupa US-001: classify_prezentare nu mai produce ramura AUTO_SEND_OPRIT.
|
||||
classify_prezentare nu mai produce ramura AUTO_SEND_OPRIT.
|
||||
O operatie cu cod rezolvat (indiferent de auto_send) -> queued direct.
|
||||
"""
|
||||
import json
|
||||
@@ -400,12 +400,12 @@ def test_auto_send_oprit_3niveluri_noul_comportament(client):
|
||||
mapping_meta = {"OP_REVIEW": {"cod_prestatie": "OE-1", "auto_send": False}}
|
||||
res = classify_prezentare(content, mapping, mapping_meta)
|
||||
assert res["status"] == "queued", (
|
||||
f"dupa US-001 auto_send=0 -> queued (nu needs_mapping), got {res['status']}"
|
||||
f"auto_send=0 -> queued (nu needs_mapping), got {res['status']}"
|
||||
)
|
||||
|
||||
|
||||
def test_needs_data_pass_through(client):
|
||||
"""VIN invalid -> needs_data; rar_error = array cu erori care au cod/problema/fix (US-002)."""
|
||||
"""VIN invalid -> needs_data; rar_error = array cu erori care au cod/problema/fix."""
|
||||
import json
|
||||
from app.mapping import classify_prezentare
|
||||
|
||||
@@ -423,7 +423,7 @@ def test_needs_data_pass_through(client):
|
||||
erori = json.loads(res["rar_error"])
|
||||
assert isinstance(erori, list)
|
||||
assert len(erori) >= 1
|
||||
# Fiecare eroare are cele 3 niveluri (pass-through US-002)
|
||||
# Fiecare eroare are cele 3 niveluri (pass-through)
|
||||
for e in erori:
|
||||
assert "cod" in e, f"lipseste 'cod' in {e}"
|
||||
assert "problema" in e, f"lipseste 'problema' in {e}"
|
||||
@@ -431,7 +431,7 @@ def test_needs_data_pass_through(client):
|
||||
|
||||
|
||||
# =========================================================================== #
|
||||
# US-001: Scoate hold auto_send din mapare — teste RED (inainte de implementare)
|
||||
# Scoate hold auto_send din mapare #
|
||||
# =========================================================================== #
|
||||
|
||||
@pytest.fixture()
|
||||
@@ -453,7 +453,7 @@ def db_conn(monkeypatch, tmp_path):
|
||||
def test_operatie_mapata_intra_in_queued_indiferent_de_autosend():
|
||||
"""classify_prezentare cu mapare auto_send=0 -> queued (nu needs_mapping).
|
||||
|
||||
Dupa US-001: has_no_auto_send nu mai blocheaza; un cod rezolvat e direct queued.
|
||||
has_no_auto_send nu mai blocheaza; un cod rezolvat e direct queued.
|
||||
"""
|
||||
from app.mapping import classify_prezentare
|
||||
content = {
|
||||
@@ -475,7 +475,7 @@ def test_operatie_mapata_intra_in_queued_indiferent_de_autosend():
|
||||
def test_regula_text_rezolvata_nu_mai_tine_randul():
|
||||
"""Regula text cu auto_send=0 rezolva codul -> queued (nu needs_mapping held).
|
||||
|
||||
Dupa US-001: regula_fara_autosend nu se mai seteaza; codul rezolvat = queued direct.
|
||||
regula_fara_autosend nu se mai seteaza; codul rezolvat = queued direct.
|
||||
"""
|
||||
from app.mapping import classify_prezentare
|
||||
content = {
|
||||
@@ -494,16 +494,16 @@ def test_regula_text_rezolvata_nu_mai_tine_randul():
|
||||
|
||||
|
||||
def test_fara_stare_needs_mapping_pe_auto_send_oprit():
|
||||
"""has_no_auto_send intotdeauna False dupa US-001; nu mai produce AUTO_SEND_OPRIT."""
|
||||
"""has_no_auto_send intotdeauna False; nu mai produce AUTO_SEND_OPRIT."""
|
||||
from app.mapping import has_no_auto_send
|
||||
mapping_meta_false = {"OP_REVIEW": {"cod_prestatie": "OE-1", "auto_send": False}}
|
||||
resolved = [{"cod_op_service": "OP_REVIEW", "cod_prestatie": "OE-1"}]
|
||||
assert has_no_auto_send(resolved, mapping_meta_false) is False, (
|
||||
"has_no_auto_send trebuie sa intoarca mereu False dupa US-001"
|
||||
"has_no_auto_send trebuie sa intoarca mereu False"
|
||||
)
|
||||
resolved_cu_flag = [{"cod_op_service": "X", "cod_prestatie": "OE-1", "regula_fara_autosend": True}]
|
||||
assert has_no_auto_send(resolved_cu_flag, {}) is False, (
|
||||
"has_no_auto_send ignora regula_fara_autosend dupa US-001"
|
||||
"has_no_auto_send ignora regula_fara_autosend"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-011 (PRD 5.8) — helper pur `text_rules_overlap`.
|
||||
"""Helper pur `text_rules_overlap`.
|
||||
|
||||
Avertisment neblocant cand o regula text noua se suprapune (substring, oricare
|
||||
directie) cu una existenta. Helper determinist, fara DB.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""US-001: Schema + persistenta reguli text de mapare (operation_text_rules).
|
||||
"""Schema + persistenta reguli text de mapare (operation_text_rules).
|
||||
|
||||
Teste RED-first: verifica tabela, functiile de persistenta si unicitatea per cont.
|
||||
Verifica tabela, functiile de persistenta si unicitatea per cont.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
"""Teste PRD 5.19 US-007 — gauge-uri /metrics pentru coada tinuta.
|
||||
"""Teste gauge-uri /metrics pentru coada tinuta.
|
||||
|
||||
/metrics expune, pe langa `autopass_submissions{status=...}`, doua gauge-uri
|
||||
DERIVATE (zero stare noua), scoped global:
|
||||
- autopass_held_submissions = COUNT(queued AND held=1)
|
||||
- autopass_held_oldest_age_seconds = varsta (s) a celui mai vechi rand tinut
|
||||
|
||||
TDD: fixtura izoleaza DB per test (pattern din test_worker_held.py).
|
||||
Fixtura izoleaza DB per test (pattern din test_worker_held.py).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Teste US-003 (PRD 5.6): logger structurat central observ.log_event.
|
||||
"""Logger structurat central observ.log_event.
|
||||
|
||||
TDD: scrie in app_events SI in log text, redacteaza creds/PII, filtreaza pe nivel.
|
||||
Scrie in app_events SI in log text, redacteaza creds/PII, filtreaza pe nivel.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -97,9 +97,9 @@ def test_nivel_filtrat_din_env(env, monkeypatch):
|
||||
def test_log_event_best_effort_nu_propaga(env, monkeypatch):
|
||||
"""O eroare interna de scriere nu propaga (jurnal best-effort)."""
|
||||
from app import observ
|
||||
# Forteaza o eroare in insert pasand o conexiune invalida
|
||||
|
||||
class Boom:
|
||||
def execute(self, *a, **k):
|
||||
raise RuntimeError("boom")
|
||||
# nu trebuie sa ridice
|
||||
|
||||
observ.log_event("nepasator", conn=Boom())
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"""US-004 (PRD 5.18) — seeder corpus etichetat in mapping_suggestions (SILVER).
|
||||
"""Seeder corpus etichetat in mapping_suggestions (SILVER).
|
||||
|
||||
INSERT OR IGNORE din artefactul comis -> SILVER nu mai e gol in productie.
|
||||
NB (F10): confirmarile UMANE stau in shared_mappings, NU aici; deci INSERT OR IGNORE
|
||||
pastreaza codul LLM existent la re-seed (v1 = ignore, nu upsert).
|
||||
Confirmarile UMANE stau in shared_mappings, NU aici; deci INSERT OR IGNORE
|
||||
pastreaza codul LLM existent la re-seed (ignore, nu upsert).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Teste US-003 (PRD 3.5): helper pur payload -> campuri afisabile.
|
||||
"""Teste helper pur payload -> campuri afisabile.
|
||||
|
||||
Helper partajat web + API (DRY, eng review). Defensiv: nu arunca pe payload
|
||||
Helper partajat web + API (DRY). Defensiv: nu arunca pe payload
|
||||
malformat; tolerant la diferentele de chei intre canale (numar vs
|
||||
numarInmatriculare) si la coercion Excel (odometru "123.0", VIN non-string).
|
||||
"""
|
||||
@@ -82,7 +82,7 @@ def test_operatie_fallback_la_cod():
|
||||
assert d["operatie"] == "OP-77"
|
||||
|
||||
|
||||
# --- US-005: cod_rar distinct ---
|
||||
# --- cod_rar distinct ---
|
||||
|
||||
def test_cod_rar_prezent_cand_mapat():
|
||||
"""cod_prestatie prezent -> cod_rar e uppercase + strip '.0'."""
|
||||
@@ -148,7 +148,7 @@ def test_operatie_ramane_denumire_sau_op():
|
||||
assert d3["cod"] == "oe-2" # cod ramas neschimbat (nu uppercase)
|
||||
|
||||
|
||||
# --- US-002: op_service_cod + op_service_denumire distincte ---
|
||||
# --- op_service_cod + op_service_denumire distincte ---
|
||||
|
||||
def test_operatie_service_din_cod_op_service():
|
||||
"""cod_op_service prezent -> op_service_cod contine valoarea; string gol cand lipseste."""
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-001/US-002 (PRD 5.17): app/plans.py — definitia planurilor + helperi tier/consum."""
|
||||
"""app/plans.py — definitia planurilor + helperi tier/consum."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -307,7 +307,7 @@ def test_consum_lunar_nu_numara_cross_account(conn):
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# PRD 5.17 enforcement — logica de limita + kill-switch config
|
||||
# Enforcement — logica de limita + kill-switch config
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_volume_la_limita_exacta(conn):
|
||||
@@ -339,8 +339,8 @@ def test_volume_la_limita_exacta(conn):
|
||||
def test_enforce_plans_config_default_true(monkeypatch):
|
||||
"""AUTOPASS_ENFORCE_PLANS implicit True — enforcement activ de la deploy.
|
||||
|
||||
Decizie user (autoplan 2026-06-28): nu exista conturi legacy, produs in TESTE,
|
||||
enforcement DUR activ implicit. Kill-switch oprit explicit cand e necesar.
|
||||
Nu exista conturi legacy; enforcement DUR activ implicit.
|
||||
Kill-switch oprit explicit cand e necesar.
|
||||
"""
|
||||
from app.config import Settings
|
||||
# Creem Settings fresh (fara env var setata) -> default True
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
"""US-001 (PRD 5.18) — pre-filtru determinist non-operatii (NUL).
|
||||
"""Pre-filtru determinist non-operatii (NUL).
|
||||
|
||||
Masuratoarea k-NN (memorie test-precizie-knn-embeddings) arata recall NUL doar 64%:
|
||||
gunoiul evident (ITP, plata, discount, nr. inmatriculare, tractare) scapa ca OE-1.
|
||||
Un pre-filtru determinist il marcheaza NUL INAINTE de k-NN.
|
||||
Recall NUL doar 64% cu k-NN: gunoiul evident (ITP, plata, discount,
|
||||
nr. inmatriculare, tractare) scapa ca OE-1. Un pre-filtru determinist il
|
||||
marcheaza NUL INAINTE de k-NN.
|
||||
|
||||
Garantie non-negociabila (AC): ZERO fals-pozitiv pe operatii reale. Regulile
|
||||
text/regex au fost calibrate pe `docs/operatii-service/*.csv` (vezi sesiunea de
|
||||
implementare): triggerele ambigue (TRACTARE, NR INMATRICULARE/placuta) sunt
|
||||
ECRANATE de un context de piesa/operatie (D/R, CARLIG, CAPAC, INLOCUIT...).
|
||||
Garantie non-negociabila: ZERO fals-pozitiv pe operatii reale. Regulile
|
||||
text/regex au fost calibrate pe `docs/operatii-service/*.csv`: triggerele
|
||||
ambigue (TRACTARE, NR INMATRICULARE/placuta) sunt ECRANATE de un context de
|
||||
piesa/operatie (D/R, CARLIG, CAPAC, INLOCUIT...).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -53,7 +53,7 @@ def test_operatie_reala_nu_e_nul():
|
||||
|
||||
|
||||
def test_zero_fals_pozitiv_pe_set_operatii_reale():
|
||||
"""AC: zero fals-pozitiv pe un set de 20 operatii reale (din docs/operatii-service)."""
|
||||
"""Zero fals-pozitiv pe un set de 20 operatii reale (din docs/operatii-service)."""
|
||||
reale = [
|
||||
"REVIZIE", "SCHIMB ULEI MOTOR", "INLOCUIT PLACUTE FRANA FATA",
|
||||
"D/R BARA FATA", "VOPSIT USA DR FATA", "INLOCUIT FILTRU AER",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
"""Teste US-002 (PRD 3.6): buton "Editeaza" pe rand in tabelul de preview.
|
||||
"""Buton "Editeaza" pe rand in tabelul de preview.
|
||||
|
||||
Mod editare pe rand (form propriu, NU #confirm-form). Swap pe rand + OOB contoare,
|
||||
NU pe #import-section (D-3.1). La eroare de validare randul ramane in editare cu
|
||||
valorile pastrate (D-2.1/D-2.2). Enter intr-un camp salveaza randul, nu confirma (D-3.3).
|
||||
NU pe #import-section. La eroare de validare randul ramane in editare cu
|
||||
valorile pastrate. Enter intr-un camp salveaza randul, nu confirma.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -98,9 +98,9 @@ def test_editeaza_intra_in_mod_editare_form_propriu(client):
|
||||
def test_salveaza_cere_reincarcare_si_toast(client):
|
||||
"""POST editeaza: raspuns minimal + HX-Trigger(reincarcaPreview + randSalvat).
|
||||
|
||||
Contractul nou (dogfood 5.13): nu mai facem OOB swap pe <tr> (fragil in htmx 1.9 ->
|
||||
randul ramanea cu starea veche). Raspunsul cere reincarcarea preview-ului si emite
|
||||
detaliile randului salvat pentru toast/evidentiere."""
|
||||
Nu se face OOB swap pe <tr> (fragil in htmx 1.9 -> randul ramanea cu starea veche).
|
||||
Raspunsul cere reincarcarea preview-ului si emite detaliile randului salvat pentru
|
||||
toast/evidentiere."""
|
||||
import json as _json
|
||||
_seed_op1()
|
||||
iid = _upload_and_preview(client)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Teste US-003 (PRD 5.11) — Preview pas 3 in format identic cu tabelul Trimiteri.
|
||||
"""Teste preview pas 3 in format identic cu tabelul Trimiteri.
|
||||
|
||||
Proces TDD: aceste teste sunt scrise INAINTE de implementare (RED) si verifica:
|
||||
Verifica:
|
||||
1. Coloana Note nu afiseaza repr Python brut (lista/dict Python) pentru needs_mapping.
|
||||
2. Starea afisata in pill-ul randului este eticheta umana (nu codul brut).
|
||||
3. Tabelul de preview foloseste clasa CSS .tabel-trimiteri.
|
||||
@@ -161,7 +161,7 @@ _ROWS_DUPLICATE = [
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Teste RED → GREEN #
|
||||
# Teste #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
def test_preview_nu_contine_repr_python(client):
|
||||
@@ -245,11 +245,10 @@ def test_preview_stare_eticheta_umana_duplicate(client):
|
||||
def test_nota_umana_preview_needs_mapping_cu_flag_prioritizeaza_unmapped():
|
||||
"""needs_mapping + flag -> Note afiseaza 'Cod RAR lipsa', nu textul flag-ului.
|
||||
|
||||
BUG 3: nota_umana_preview verifica `if flags:` inaintea ramurei unmapped.
|
||||
Un rand needs_mapping care are si un flag (ex. VIN numeric) afisa textul
|
||||
flag-ului in loc de 'Cod RAR lipsa pentru: COD' — exact confuzia US-003
|
||||
voia s-o evite (userul corecteaza data si ramane blocat pe cod).
|
||||
Fix: cand status == 'needs_mapping', prioritizeaza ramura unmapped.
|
||||
Un rand needs_mapping care are si un flag (ex. VIN numeric) nu trebuie sa
|
||||
afiseze textul flag-ului in loc de 'Cod RAR lipsa pentru: COD' (userul ar
|
||||
corecta data si ar ramane blocat pe cod). Cand status == 'needs_mapping',
|
||||
nota_umana_preview prioritizeaza ramura unmapped.
|
||||
"""
|
||||
from app.web.labels import nota_umana_preview
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-013 (PRD 5.6): retentie / purjare randuri ne-sent blocate."""
|
||||
"""Teste retentie / purjare randuri ne-sent blocate."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""US-002 (PRD 5.20): medii_disponibile + rar_env_efectiv (REQ-DISP / REQ-DEFAULT)."""
|
||||
"""medii_disponibile + rar_env_efectiv (REQ-DISP / REQ-DEFAULT)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-004 (PRD 5.20): rezolvare mediu tinta la ingestie + respingere tinte indisponibile.
|
||||
"""Rezolvare mediu tinta la ingestie + respingere tinte indisponibile.
|
||||
|
||||
Fixtura `conn` urmareste acelasi pattern ca tests/test_accounts.py:
|
||||
monkeypatch AUTOPASS_DB_PATH pe tempdir, cache_clear, init_db, get_connection.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-002 (PRD 5.6): request_id per cerere + header X-Request-ID."""
|
||||
"""Teste request_id per cerere + header X-Request-ID."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
"""US-003: Reguli text active la ingestie (API + import + corectie web) si la
|
||||
"""Reguli text active la ingestie (API + import + corectie web) si la
|
||||
re-rezolvarea blocajelor (`reresolve_account`).
|
||||
|
||||
Verifica ca o regula text salvata in prealabil rezolva o operatie fara mapare
|
||||
exacta pe TOATE caile de ingestie, in loc sa o lase `needs_mapping`, si ca la
|
||||
re-rezolvare un rand `needs_mapping` care acum da match pe o regula se deblocheaza.
|
||||
|
||||
Codul rezolvat din regula respecta validarea fata de nomenclator (US-002): folosim
|
||||
Codul rezolvat din regula respecta validarea fata de nomenclator: folosim
|
||||
`OE-2`, cod valid din seed-ul nomenclatorului.
|
||||
"""
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-013 (PRD 5.20): retragere coloana legacy accounts.rar_creds_enc.
|
||||
"""Retragere coloana legacy accounts.rar_creds_enc.
|
||||
|
||||
Teste:
|
||||
test_niciun_read_pe_coloana_veche -- DB fresh: accounts N-are rar_creds_enc, submissions ARE
|
||||
@@ -236,7 +236,7 @@ def test_are_creds_pe_per_env(client):
|
||||
def test_drop_cu_garda_blocat_daca_lipsa_copiere(conn_izolat):
|
||||
"""Garda refuza DROP cand exista cont cu rar_creds_enc dar ambele sloturi per-env goale.
|
||||
|
||||
Apelam _garda_si_drop direct (fara re-backfill 6c) pe o stare adversariala:
|
||||
Apelam _garda_si_drop direct (fara re-backfill) pe o stare adversariala:
|
||||
cont cu valoare in coloana legacy, rar_creds_test_enc=NULL, rar_creds_prod_enc=NULL.
|
||||
Rezultat asteptat: DROP refuzat (coloana inca prezenta pe accounts).
|
||||
"""
|
||||
@@ -263,7 +263,7 @@ def test_drop_cu_garda_blocat_daca_lipsa_copiere(conn_izolat):
|
||||
assert row_before["rar_creds_test_enc"] is None
|
||||
assert row_before["rar_creds_prod_enc"] is None
|
||||
|
||||
# Apelam _garda_si_drop direct (fara re-backfill 6c)
|
||||
# Apelam _garda_si_drop direct (fara re-backfill)
|
||||
from app.db import _garda_si_drop
|
||||
_garda_si_drop(conn)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""US-001 (PRD 5.20): schema medii per cont + env pe submission + migrare/backfill."""
|
||||
"""Schema medii per cont + env pe submission + migrare/backfill."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -26,7 +26,7 @@ def fresh_conn(monkeypatch):
|
||||
|
||||
|
||||
def _old_db(path: str) -> sqlite3.Connection:
|
||||
"""Construieste un DB in forma PRE-5.20 (fara coloanele de mediu)."""
|
||||
"""Construieste un DB in forma veche (fara coloanele de mediu)."""
|
||||
conn = sqlite3.connect(path, isolation_level=None)
|
||||
conn.row_factory = sqlite3.Row
|
||||
conn.execute(
|
||||
@@ -109,7 +109,7 @@ def test_migrare_cont_fara_creds_ramane_pe_default(tmp_path, monkeypatch):
|
||||
|
||||
|
||||
def test_submissions_rar_env(tmp_path, monkeypatch):
|
||||
"""Un rand PRE-migrare ajunge cu env-ul global (NU 'test') + cheie recalculata env-aware."""
|
||||
"""Un rand pre-migrare ajunge cu env-ul global (NU 'test') + cheie recalculata env-aware."""
|
||||
path = str(tmp_path / "old.db")
|
||||
old = _old_db(path)
|
||||
payload = {
|
||||
|
||||
@@ -148,7 +148,7 @@ def test_prod_requires_key(env):
|
||||
conn = get_connection()
|
||||
try:
|
||||
key = create_api_key(conn, 1)
|
||||
# Testul verifica autentificarea, nu planul — tier='pro' ca sa treaca gate-ul API (T4).
|
||||
# Testul verifica autentificarea, nu planul — tier='pro' ca sa treaca gate-ul API.
|
||||
conn.execute("UPDATE accounts SET tier='pro' WHERE id=1")
|
||||
finally:
|
||||
conn.close()
|
||||
@@ -186,7 +186,7 @@ def test_key_account_routes_idempotency(env):
|
||||
|
||||
conn = get_connection()
|
||||
try:
|
||||
# tier='pro' pe ambele conturi — testul verifica idempotenta, nu planuri (T4 PRD 5.17).
|
||||
# tier='pro' pe ambele conturi — testul verifica idempotenta, nu planuri.
|
||||
conn.execute("UPDATE accounts SET tier='pro' WHERE id=1")
|
||||
conn.execute("INSERT INTO accounts (id, name, tier) VALUES (2, 'al-doilea', 'pro')")
|
||||
k1 = create_api_key(conn, 1)
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
"""Teste US-001 (PRD 5.12): companie/email/CUI obligatorii la signup.
|
||||
|
||||
TDD strict: testele se scriu INAINTE de implementare (RED), dupa implementare trec (GREEN).
|
||||
"""
|
||||
"""Companie/email/CUI obligatorii la signup."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -37,7 +34,7 @@ def _csrf(html: str) -> str:
|
||||
|
||||
|
||||
def test_signup_html_cui_obligatoriu_ui(client):
|
||||
"""GET /signup: campul CUI NU contine '(optional)' si are atribut required (US-001 UI)."""
|
||||
"""GET /signup: campul CUI NU contine '(optional)' si are atribut required."""
|
||||
resp = client.get("/signup")
|
||||
assert resp.status_code == 200
|
||||
# (a) NU trebuie sa apara textul "(optional)" langa CUI
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
"""Teste US-012 (PRD 3.3b): notificare email admin la signup (degradat) + bootstrap admin.
|
||||
|
||||
TDD: testele se scriu INAINTE de implementare; la inceput pica (RED),
|
||||
dupa implementare trec (GREEN).
|
||||
"""
|
||||
"""Notificare email admin la signup (degradat) + bootstrap admin."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -152,13 +148,13 @@ def test_primul_signup_devine_admin(client):
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Teste C16 (log SIGNUP pastrat) si best-effort E2E
|
||||
# Teste log SIGNUP pastrat si best-effort E2E
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_signup_logheaza_fara_pii_in_stdout(client, capsys):
|
||||
"""Signup reusit -> NU se mai printeaza email-ul in clar in stdout (P2-7).
|
||||
"""Signup reusit -> NU se mai printeaza email-ul in clar in stdout.
|
||||
|
||||
C16 (jurnalizarea signup-ului) e pastrata, dar prin `log_event` (app_events +
|
||||
Jurnalizarea signup-ului e pastrata, dar prin `log_event` (app_events +
|
||||
log text redactat), nu prin print() cu PII."""
|
||||
resp = _do_signup(client, "Service Log Test", "log@test.com")
|
||||
assert resp.status_code == 200
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-011 (PRD 5.20): indicator mediu RAR in statusbar + toggle conditionat.
|
||||
"""Indicator mediu RAR in statusbar + toggle conditionat.
|
||||
|
||||
Rute testate:
|
||||
GET /_fragments/status -- indicator mediu (eticheta statica sau toggle)
|
||||
@@ -135,7 +135,7 @@ def _get_csrf_din_status(client) -> str:
|
||||
def test_afiseaza_env_default(client):
|
||||
"""Cont cu UN singur mediu disponibil (prod) -> statusbar contine eticheta pentru Productie,
|
||||
fara niciun control de toggle/comutare.
|
||||
US-010 (PRD 5.20): eticheta foloseste acum 'PRODUCȚIE' (diacritice + majuscule).
|
||||
Eticheta foloseste 'PRODUCȚIE' (diacritice + majuscule).
|
||||
"""
|
||||
acct_id, _ = _create_account_user("Firma Env1", "env1@test.com")
|
||||
_seteaza_mediu_disponibil(acct_id, "prod")
|
||||
@@ -145,7 +145,7 @@ def test_afiseaza_env_default(client):
|
||||
assert resp.status_code == 200, f"Status HTTP neasteptat: {resp.status_code}"
|
||||
html = resp.text
|
||||
|
||||
# Eticheta mediului trebuie prezenta — "PRODUC" acopera atat 'PRODUCȚIE' (US-010) cat si
|
||||
# Eticheta mediului trebuie prezenta — "PRODUC" acopera atat 'PRODUCȚIE' cat si
|
||||
# formele anterioare 'Productie'/'PRODUCTIE' (anti-regresie).
|
||||
assert "PRODUC" in html.upper(), f"Eticheta Productie absenta in statusbar: {html[:800]}"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-009 (PRD 5.6): helper sterge / re-pune in coada randuri blocate."""
|
||||
"""Helper sterge / re-pune in coada randuri blocate."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste T16: job purjare + purge_after SET la insert (OV-5).
|
||||
"""Job purjare + purge_after SET la insert.
|
||||
|
||||
Verify:
|
||||
(a) insert/sent -> purge_after populat (sent+90z).
|
||||
@@ -68,7 +68,7 @@ def test_mark_sent_seteaza_purge_after(conn):
|
||||
def test_mark_queued_nu_seteaza_purge_after(conn):
|
||||
"""Starile active (queued) nu primesc purge_after.
|
||||
|
||||
NOTA US-013: error/needs_data/needs_mapping primesc ACUM purge_after (retentie
|
||||
NOTA: error/needs_data/needs_mapping primesc ACUM purge_after (retentie
|
||||
blocate, 30z) — vezi tests/test_purge_blocate.py. Doar queued/sending raman fara.
|
||||
"""
|
||||
import app.worker.__main__ as w
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
"""Teste T1: creds durabile per-cont (per-env, US-013) + worker re-login fallback + gate purjare.
|
||||
"""Creds durabile per-cont (per-env) + worker re-login fallback + gate purjare.
|
||||
|
||||
Verify:
|
||||
(a) Serie web, worker restart (sesiune goala), token expirat -> re-login din accounts -> trimite.
|
||||
(b) Coada MIXTA API(efemer)+web(durabil): dupa login web, submission-urile API tot se trimit
|
||||
(purjarea nu le-a rupt prematur).
|
||||
|
||||
US-013: accounts.rar_creds_enc (legacy) a fost dropata; sloturile per-env sunt singura sursa.
|
||||
accounts.rar_creds_enc (legacy) a fost dropata; sloturile per-env sunt singura sursa.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -83,7 +83,7 @@ def test_creds_from_account_fallback(env, monkeypatch):
|
||||
conn = get_connection()
|
||||
try:
|
||||
enc = encrypt_creds({"email": "web@test.ro", "password": "webpass"})
|
||||
# US-013: scrie in slotul per-env test (slotul legacy rar_creds_enc dropat)
|
||||
# scrie in slotul per-env test (slotul legacy rar_creds_enc dropat)
|
||||
conn.execute(
|
||||
"UPDATE accounts SET rar_creds_test_enc=?, rar_test_enabled=1 WHERE id=1", (enc,)
|
||||
)
|
||||
@@ -122,7 +122,7 @@ def test_worker_relogin_dupa_restart(env, monkeypatch):
|
||||
conn = get_connection()
|
||||
try:
|
||||
enc = encrypt_creds({"email": "web@test.ro", "password": "webpass"})
|
||||
# US-013: scrie in slotul per-env test
|
||||
# scrie in slotul per-env test
|
||||
conn.execute(
|
||||
"UPDATE accounts SET rar_creds_test_enc=?, rar_test_enabled=1 WHERE id=1", (enc,)
|
||||
)
|
||||
@@ -152,7 +152,7 @@ def test_coada_mixta_api_web(env, monkeypatch):
|
||||
1. S1 = submission API cu creds efemere in submissions.rar_creds_enc
|
||||
2. S2 = submission WEB fara creds (foloseste accounts.rar_creds_test_enc per-env)
|
||||
3. Login cu creds S1 -> purjare S1.rar_creds_enc (pe submissions) -> OK (worker are token)
|
||||
4. S2 tot se poate procesa (creds din accounts per-env, US-013)
|
||||
4. S2 tot se poate procesa (creds din accounts per-env)
|
||||
"""
|
||||
import app.worker.__main__ as w
|
||||
from app.crypto import encrypt_creds
|
||||
@@ -162,7 +162,7 @@ def test_coada_mixta_api_web(env, monkeypatch):
|
||||
|
||||
conn = get_connection()
|
||||
try:
|
||||
# Creds durabile pentru contul web (slotul per-env, US-013)
|
||||
# Creds durabile pentru contul web (slotul per-env)
|
||||
enc_web = encrypt_creds({"email": "web@test.ro", "password": "webpass"})
|
||||
conn.execute(
|
||||
"UPDATE accounts SET rar_creds_test_enc=?, rar_test_enabled=1 WHERE id=1", (enc_web,)
|
||||
@@ -209,7 +209,7 @@ def client(env):
|
||||
|
||||
|
||||
def test_endpoint_set_rar_creds(client, env):
|
||||
"""POST /v1/conturi/rar-creds seteaza creds criptate in slotul per-env (US-013)."""
|
||||
"""POST /v1/conturi/rar-creds seteaza creds criptate in slotul per-env."""
|
||||
from app.crypto import decrypt_creds
|
||||
from app.db import get_connection
|
||||
|
||||
@@ -235,7 +235,7 @@ def test_endpoint_set_rar_creds(client, env):
|
||||
|
||||
|
||||
def test_endpoint_delete_rar_creds(client, env):
|
||||
"""DELETE /v1/conturi/rar-creds sterge creds durabile (ambele sloturi per-env, US-013)."""
|
||||
"""DELETE /v1/conturi/rar-creds sterge creds durabile (ambele sloturi per-env)."""
|
||||
# Mai intai seteaza pe test si prod
|
||||
client.post("/v1/conturi/rar-creds", json={"email": "u@test.ro", "password": "pass123", "rar_target": "test"})
|
||||
client.post("/v1/conturi/rar-creds", json={"email": "u@prod.ro", "password": "pass456", "rar_target": "prod"})
|
||||
@@ -257,7 +257,7 @@ def test_endpoint_delete_rar_creds(client, env):
|
||||
|
||||
|
||||
def test_gate_purjare_nu_sterge_accounts(env, monkeypatch):
|
||||
"""Gate purjare T1: stergerea submissions.rar_creds_enc NU atinge accounts per-env (US-013)."""
|
||||
"""Gate purjare: stergerea submissions.rar_creds_enc NU atinge accounts per-env."""
|
||||
import app.worker.__main__ as w
|
||||
from app.crypto import encrypt_creds
|
||||
from app.db import get_connection
|
||||
@@ -267,7 +267,7 @@ def test_gate_purjare_nu_sterge_accounts(env, monkeypatch):
|
||||
conn = get_connection()
|
||||
try:
|
||||
enc = encrypt_creds({"email": "u@test.ro", "password": "p"})
|
||||
# US-013: scrie in slotul per-env test
|
||||
# scrie in slotul per-env test
|
||||
conn.execute(
|
||||
"UPDATE accounts SET rar_creds_test_enc=?, rar_test_enabled=1 WHERE id=1", (enc,)
|
||||
)
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
"""Teste T6: comportament dupa US-001 (PRD 5.11) — auto_send nu mai tine randuri.
|
||||
"""auto_send nu mai tine randuri.
|
||||
|
||||
US-001: has_no_auto_send neutralizat (return False); un cod rezolvat (mapare exacta
|
||||
has_no_auto_send neutralizat (return False); un cod rezolvat (mapare exacta
|
||||
sau regula text) -> queued direct, indiferent de auto_send=0/1 in mapping_meta.
|
||||
|
||||
Coloanele DB operations_mapping.auto_send si operation_text_rules.auto_send RAMAN
|
||||
(default 1, ne-citite pentru hold). Functia has_no_auto_send RAMANE DEFINITA (importata
|
||||
in routes.py + import_router.py) dar intoarce mereu False.
|
||||
|
||||
Inainte de US-001:
|
||||
(a) cod nou-mapat cu auto_send=0 -> nu auto-send, review manual (needs_mapping).
|
||||
Comportament:
|
||||
(a) cod nou-mapat cu auto_send=0 -> queued.
|
||||
(b) mapare existenta cu auto_send=1 -> queued.
|
||||
Dupa US-001:
|
||||
(a) cod nou-mapat cu auto_send=0 -> queued (ca si (b)).
|
||||
(b) mapare existenta cu auto_send=1 -> queued (neschimbat).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -93,7 +90,7 @@ def test_load_mapping_meta_returns_auto_send(conn):
|
||||
# --- has_no_auto_send (neutralizat, mereu False) ---
|
||||
|
||||
def test_has_no_auto_send_mereu_false_cu_auto_send_fals(conn):
|
||||
"""has_no_auto_send intoarce False chiar si cand auto_send=False in mapping_meta (US-001)."""
|
||||
"""has_no_auto_send intoarce False chiar si cand auto_send=False in mapping_meta."""
|
||||
from app.mapping import has_no_auto_send
|
||||
mapping_meta = {
|
||||
"ITP-1": {"cod_prestatie": "OE-1", "auto_send": False},
|
||||
@@ -120,10 +117,10 @@ def test_has_no_auto_send_direct_cod_prestatie(conn):
|
||||
assert has_no_auto_send(resolved, mapping_meta) is False
|
||||
|
||||
|
||||
# --- reresolve_account cu auto_send=0 (US-001: acum requeue) ---
|
||||
# --- reresolve_account cu auto_send=0 (acum requeue) ---
|
||||
|
||||
def test_reresolve_auto_send_zero_acum_requeue(conn):
|
||||
"""(US-001) cod nou-mapat cu auto_send=0 -> queued (nu mai review_manual)."""
|
||||
"""cod nou-mapat cu auto_send=0 -> queued (nu mai review_manual)."""
|
||||
from app.mapping import reresolve_account
|
||||
sid = _insert_needs_mapping(conn, cod_op="ITP-CHECK")
|
||||
_add_mapping(conn, cod_op="ITP-CHECK", cod_prestatie="OE-1", auto_send=False)
|
||||
@@ -150,7 +147,7 @@ def test_reresolve_auto_send_unu_requeue(conn):
|
||||
assert row["status"] == "queued"
|
||||
|
||||
|
||||
# --- POST /v1/prezentari cu auto_send=0 (US-001: acum queued) ---
|
||||
# --- POST /v1/prezentari cu auto_send=0 (acum queued) ---
|
||||
|
||||
def _body_with_op(cod_op="ITP-CHECK"):
|
||||
return {
|
||||
@@ -166,7 +163,7 @@ def _body_with_op(cod_op="ITP-CHECK"):
|
||||
|
||||
|
||||
def test_post_auto_send_zero_acum_queued(client, env):
|
||||
"""(US-001) Via API: cod nou-mapat cu auto_send=0 -> queued (nu mai needs_mapping)."""
|
||||
"""Via API: cod nou-mapat cu auto_send=0 -> queued (nu mai needs_mapping)."""
|
||||
from app.db import get_connection
|
||||
conn2 = get_connection()
|
||||
try:
|
||||
@@ -177,7 +174,7 @@ def test_post_auto_send_zero_acum_queued(client, env):
|
||||
r = client.post("/v1/prezentari", json=_body_with_op("ITP-X"))
|
||||
assert r.status_code == 200
|
||||
status = r.json()["results"][0]["status"]
|
||||
assert status == "queued", f"auto_send=0 dupa US-001 -> queued, e: {status}"
|
||||
assert status == "queued", f"auto_send=0 -> queued, e: {status}"
|
||||
|
||||
|
||||
def test_post_auto_send_unu_queued(client, env):
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
"""Teste US-001 + US-002 (PRD 5.3): Light/Dark mode comutator tema.
|
||||
|
||||
TDD: testele se scriu INAINTE de implementare (RED), dupa implementare trec (GREEN).
|
||||
"""
|
||||
"""Light/Dark mode comutator tema."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -52,7 +49,7 @@ def _login(client, email: str, password: str = "parolasecreta") -> None:
|
||||
assert resp.status_code == 303, f"Login esuat: {resp.status_code}"
|
||||
|
||||
|
||||
# ── US-001: Tema light ─────────────────────────────────────────────────────────
|
||||
# ── Tema light ─────────────────────────────────────────────────────────────────
|
||||
|
||||
def test_paleta_light_definita(client):
|
||||
"""HTML de la GET /login contine un selector [data-theme="light"] care redefineste
|
||||
@@ -72,7 +69,7 @@ def test_paleta_light_definita(client):
|
||||
|
||||
def test_dark_ramane_default(client):
|
||||
""":root contine paleta dark exacta: --bg:#0f1218, --card:#181c24, --ink:#e6e9ef.
|
||||
Valorile actualizate la US-013 (PRD 5.10) conform DESIGN.md (accent azur ROMFAST).
|
||||
Conform DESIGN.md (accent azur ROMFAST).
|
||||
"""
|
||||
resp = client.get("/login")
|
||||
assert resp.status_code == 200
|
||||
@@ -98,7 +95,7 @@ def test_suprafete_fara_fundal_hardcodat(client):
|
||||
assert "#16241c" not in style, "Fundalul hardcodat #16241c (flash) inca in <style>"
|
||||
|
||||
|
||||
# ── US-002: Comutator tema + anti-FOUC ────────────────────────────────────────
|
||||
# ── Comutator tema + anti-FOUC ─────────────────────────────────────────────────
|
||||
|
||||
def test_script_antifouc_in_head_inainte_de_style(client):
|
||||
"""<head> contine un <script> care citeste localStorage (cheia 'theme') si seteaza
|
||||
@@ -166,7 +163,7 @@ def test_toggle_pe_login_si_dashboard(client):
|
||||
), "Butonul toggle lipseste pe dashboard"
|
||||
|
||||
|
||||
# ── US-003: Fragmente HTMX fara fundal hardcodat ──────────────────────────────
|
||||
# ── Fragmente HTMX fara fundal hardcodat ───────────────────────────────────────
|
||||
|
||||
def test_fragmente_fara_fundal_hardcodat():
|
||||
"""Niciun fisier _*.html din app/web/templates/ nu contine literalii hex dark-fix
|
||||
@@ -188,7 +185,7 @@ def test_fragmente_fara_fundal_hardcodat():
|
||||
)
|
||||
|
||||
|
||||
# ── US-001 (PRD 5.15): Teme aditive + tokeni --card2/--line2 ──────────────────
|
||||
# ── Teme aditive + tokeni --card2/--line2 ──────────────────────────────────────
|
||||
|
||||
def test_cele_4_teme_definite(client):
|
||||
"""Cele 4 teme noi (grafit/cobalt/cupru/hartie) au blocuri CSS [data-theme="..."]
|
||||
@@ -326,12 +323,12 @@ def test_themes_dry_single_source(client):
|
||||
)
|
||||
|
||||
|
||||
# ── US-008: Test parametrizat robust — token critic in fiecare tema ─────────────
|
||||
# ── Test parametrizat robust — token critic in fiecare tema ────────────────────
|
||||
|
||||
@pytest.mark.parametrize("token", ["--card2", "--line2", "--accent", "--ok", "--err"])
|
||||
@pytest.mark.parametrize("tema", ["light", "dark", "petrol", "grafit", "cobalt", "cupru", "hartie"])
|
||||
def test_token_critic_in_tema_parametrizat(client, tema, token):
|
||||
"""US-008: test parametrizat robust — fiecare token critic e definit in fiecare tema.
|
||||
"""Test parametrizat robust — fiecare token critic e definit in fiecare tema.
|
||||
|
||||
Ancorare pe selectorul CSS [data-theme="X"] {...} (sau :root pentru dark),
|
||||
NU pe felii fixe [idx:idx+N]. Evita false-green-ul din regresia 5.13:
|
||||
@@ -372,24 +369,24 @@ def test_token_critic_in_tema_parametrizat(client, tema, token):
|
||||
)
|
||||
|
||||
|
||||
# ── US-001 PRD 5.16: Stiva font sistem standard web ───────────────────────────
|
||||
# ── Stiva font sistem standard web ─────────────────────────────────────────────
|
||||
|
||||
def test_font_stack_system_in_base(client):
|
||||
"""T-E2 (PRD 5.16): base.html DEFINESTE --font-ui si --font-mono in :root
|
||||
"""base.html DEFINESTE --font-ui si --font-mono in :root
|
||||
si body foloseste var(--font-ui). Niciun @font-face IBM Plex nu mai exista."""
|
||||
resp = client.get("/login")
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
|
||||
assert "--font-ui" in html, "Token --font-ui lipseste din :root (US-001 PRD 5.16)"
|
||||
assert "--font-mono" in html, "Token --font-mono lipseste din :root (US-001 PRD 5.16)"
|
||||
assert "var(--font-ui)" in html, "body nu foloseste var(--font-ui) (US-001 PRD 5.16)"
|
||||
assert "--font-ui" in html, "Token --font-ui lipseste din :root"
|
||||
assert "--font-mono" in html, "Token --font-mono lipseste din :root"
|
||||
assert "var(--font-ui)" in html, "body nu foloseste var(--font-ui)"
|
||||
assert "@font-face" not in html, \
|
||||
"@font-face inca prezent in base.html — sterge toate regulile IBM Plex (US-001 PRD 5.16)"
|
||||
"@font-face inca prezent in base.html — sterge toate regulile IBM Plex"
|
||||
|
||||
|
||||
def test_zero_referinte_static_fonts(client):
|
||||
"""T-E1 (PRD 5.16): nicio referinta /static/fonts/ in template-urile randate de app.
|
||||
"""Nicio referinta /static/fonts/ in template-urile randate de app.
|
||||
Toate literalele 'IBM Plex Sans' si 'IBM Plex Mono' sunt eliminate."""
|
||||
resp = client.get("/login")
|
||||
assert resp.status_code == 200
|
||||
@@ -404,24 +401,24 @@ def test_zero_referinte_static_fonts(client):
|
||||
|
||||
|
||||
def test_landing_fara_font_face_ibm_plex():
|
||||
"""T-E1 (PRD 5.16): landing.html nu contine @font-face IBM Plex si niciun
|
||||
"""landing.html nu contine @font-face IBM Plex si niciun
|
||||
literal 'IBM Plex Sans' sau 'IBM Plex Mono' ca font primary."""
|
||||
landing = Path(__file__).parent.parent / "app" / "web" / "templates" / "landing.html"
|
||||
assert landing.exists(), f"landing.html negasit la {landing}"
|
||||
content = landing.read_text(encoding="utf-8")
|
||||
|
||||
assert "@font-face" not in content, \
|
||||
"@font-face inca in landing.html — sterge toate regulile IBM Plex (US-008 PRD 5.16)"
|
||||
"@font-face inca in landing.html — sterge toate regulile IBM Plex"
|
||||
assert "IBM Plex Sans" not in content, \
|
||||
"Literal 'IBM Plex Sans' inca in landing.html — inlocuieste cu var(--font-ui)"
|
||||
assert "IBM Plex Mono" not in content, \
|
||||
"Literal 'IBM Plex Mono' inca in landing.html — inlocuieste cu var(--font-mono)"
|
||||
|
||||
|
||||
# ── US-002 PRD 5.16: Scala tipografica ────────────────────────────────────────
|
||||
# ── Scala tipografica ───────────────────────────────────────────────────────────
|
||||
|
||||
def test_tokeni_scala_fs_definiti(client):
|
||||
"""US-002 (PRD 5.16): tokenurile de scala tipografica --fs-xs..--fs-3xl si
|
||||
"""Tokenurile de scala tipografica --fs-xs..--fs-3xl si
|
||||
--lh-tight/--lh-body sunt definiti in :root."""
|
||||
resp = client.get("/login")
|
||||
assert resp.status_code == 200
|
||||
@@ -433,21 +430,21 @@ def test_tokeni_scala_fs_definiti(client):
|
||||
"--lh-tight", "--lh-body",
|
||||
]
|
||||
for tok in tokeni:
|
||||
assert tok in html, f"Token {tok} lipseste din :root (US-002 PRD 5.16)"
|
||||
assert tok in html, f"Token {tok} lipseste din :root"
|
||||
|
||||
|
||||
# ── US-011 PRD 5.16: Selector tema pill cu eticheta ───────────────────────────
|
||||
# ── Selector tema pill cu eticheta ─────────────────────────────────────────────
|
||||
|
||||
def test_selector_tema_are_eticheta(client):
|
||||
"""US-011 (PRD 5.16): butonul de tema este un pill cu clasa .tema-btn,
|
||||
"""Butonul de tema este un pill cu clasa .tema-btn,
|
||||
contine .tema-icon si #tema-label (eticheta vizibila a temei curente)."""
|
||||
resp = client.get("/login")
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
|
||||
assert "tema-btn" in html, \
|
||||
"Clasa .tema-btn lipseste din HTML — butonul de tema nu e pill (US-011 PRD 5.16)"
|
||||
"Clasa .tema-btn lipseste din HTML — butonul de tema nu e pill"
|
||||
assert "tema-icon" in html, \
|
||||
".tema-icon lipseste — iconita temei nu e separat de eticheta (US-011 PRD 5.16)"
|
||||
".tema-icon lipseste — iconita temei nu e separat de eticheta"
|
||||
assert 'id="tema-label"' in html, \
|
||||
'#tema-label lipseste — eticheta temei nu e prezenta in pill (US-011 PRD 5.16)'
|
||||
'#tema-label lipseste — eticheta temei nu e prezenta in pill'
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
"""Teste reguli text + auto_send dupa US-001 (PRD 5.11).
|
||||
"""Teste reguli text + auto_send.
|
||||
|
||||
Inainte de US-001: o regula text cu auto_send=0 tinea randul in needs_mapping
|
||||
(regula_fara_autosend=True + has_no_auto_send -> True).
|
||||
|
||||
Dupa US-001: has_no_auto_send mereu False; o regula text cu auto_send=0 rezolva
|
||||
has_no_auto_send e mereu False; o regula text cu auto_send=0 rezolva
|
||||
codul RAR si randul intra in queued direct. regula_fara_autosend nu se mai seteaza.
|
||||
|
||||
Functii pure -> teste fara DB.
|
||||
@@ -28,7 +25,7 @@ def _content_cu(op_denumire="Verificare faruri"):
|
||||
|
||||
|
||||
def test_regula_auto_send_0_acum_queued():
|
||||
"""Regula text auto_send=0 + continut valid -> queued (nu mai needs_mapping) dupa US-001."""
|
||||
"""Regula text auto_send=0 + continut valid -> queued (nu needs_mapping)."""
|
||||
tr = [{"pattern": "verificare", "cod_prestatie": "OE-2", "auto_send": 0, "priority": 0}]
|
||||
cl = classify_prezentare(_content_cu(), {}, {}, VALID, tr)
|
||||
assert cl["status"] == "queued", f"asteptat queued (auto_send ignorat), got {cl['status']}"
|
||||
@@ -42,16 +39,16 @@ def test_regula_auto_send_1_trece_in_coada():
|
||||
|
||||
|
||||
def test_has_no_auto_send_mereu_false_cu_flag_regula():
|
||||
"""has_no_auto_send=False chiar daca regula_fara_autosend e prezent (US-001)."""
|
||||
"""has_no_auto_send=False chiar daca regula_fara_autosend e prezent."""
|
||||
tr = [{"pattern": "verificare", "cod_prestatie": "OE-2", "auto_send": 0, "priority": 0}]
|
||||
resolved, unmapped = resolve_prestatii(
|
||||
[{"cod_op_service": "X99", "denumire": "Verificare faruri"}], {}, VALID, tr
|
||||
)
|
||||
assert unmapped == []
|
||||
assert resolved[0]["cod_prestatie"] == "OE-2"
|
||||
# Flagul regula_fara_autosend nu se mai seteaza (US-001)
|
||||
# Flagul regula_fara_autosend nu se mai seteaza
|
||||
assert resolved[0].get("regula_fara_autosend") is None, (
|
||||
"regula_fara_autosend nu trebuie sa mai fie setat dupa US-001"
|
||||
"regula_fara_autosend nu trebuie sa mai fie setat"
|
||||
)
|
||||
assert has_no_auto_send(resolved, {}) is False
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""US-010: Telemetrie hit regula text in `app_events`.
|
||||
"""Telemetrie hit regula text in `app_events`.
|
||||
|
||||
Cand o operatie nemapata primeste cod RAR dintr-o regula text (substring), apelantii
|
||||
cu `conn` (ingestie API, import, re-rezolvare) emit un eveniment `text_rule_hit` in
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-002 (PRD 3.1): CLI tools/account.py (create/list/activate/deactivate)."""
|
||||
"""CLI tools/account.py (create/list/activate/deactivate)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-004 (PRD 3.6): zona de upload comprimata la o bara slim.
|
||||
"""Zona de upload comprimata la o bara slim.
|
||||
|
||||
Cand contul are deja trimiteri, upload-ul devine o bara pe un rand (eticheta + buton
|
||||
+ zona de trage). First-run pastreaza hero-ul "Primul fisier?". Drag-drop + input file
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-001 (PRD 3.3): tabela users + helper-e parole scrypt in app/users.py."""
|
||||
"""Tabela users + helper-e parole scrypt in app/users.py."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -83,7 +83,7 @@ def test_get_user_by_email(conn, account_id):
|
||||
|
||||
|
||||
def test_parola_scurta_si_lunga_eroare(conn, account_id):
|
||||
"""Parola < 10 caractere sau > 128 ridica ValueError (C9 anti-DoS)."""
|
||||
"""Parola < 10 caractere sau > 128 ridica ValueError (anti-DoS)."""
|
||||
from app.users import create_user
|
||||
with pytest.raises(ValueError):
|
||||
create_user(conn, account_id, "scurta@ex.ro", "scurt")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste TDD pentru POST /v1/prezentari/valideaza (dry-run, PRD 5.2 US-001)."""
|
||||
"""Teste pentru POST /v1/prezentari/valideaza (dry-run)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -160,11 +160,11 @@ def test_shape_invalid_422(client):
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# US-003: 3 niveluri in raspunsul /valideaza #
|
||||
# 3 niveluri in raspunsul /valideaza #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
def test_erori_au_3niveluri(client):
|
||||
"""/valideaza cu VIN invalid -> erori[i] au cod/problema/cauza/fix (pass-through US-002)."""
|
||||
"""/valideaza cu VIN invalid -> erori[i] au cod/problema/cauza/fix (pass-through)."""
|
||||
r = client.post("/v1/prezentari/valideaza", json=_body_v(vin="WVWZZZ1OZIQ45678"))
|
||||
assert r.status_code == 200
|
||||
res = r.json()["results"][0]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Teste US-007 (PRD 5.20): validare credentiale RAR pe env-ul setului de creds.
|
||||
"""Validare credentiale RAR pe env-ul setului de creds.
|
||||
|
||||
Premisa confirmata live (2026-06-29): creds prod NU se valideaza pe RAR test si
|
||||
Premisa confirmata live: creds prod NU se valideaza pe RAR test si
|
||||
invers (401 incrucisat). Deci login-ul de proba TREBUIE sa loveasca endpoint-ul
|
||||
mediului caruia ii apartin credentialele, nu URL-ul global AUTOPASS_RAR_ENV.
|
||||
|
||||
@@ -97,7 +97,7 @@ class _RarClientFail:
|
||||
def test_valideaza_pe_env_creds(env_db, monkeypatch):
|
||||
"""Cand validezi creds pentru env='prod', clientul de login e creat cu base_url-ul prod.
|
||||
|
||||
US-007 AC: 'validarea foloseste env-ul setului de creds verificat'.
|
||||
Validarea foloseste env-ul setului de creds verificat.
|
||||
Premisa: creds prod nu se valideaza pe RAR test (401 incrucisat), deci
|
||||
clientul TREBUIE sa foloseasca base_url-ul prod, nu cel de test.
|
||||
"""
|
||||
@@ -146,8 +146,8 @@ def test_valideaza_pe_env_creds_test(env_db, monkeypatch):
|
||||
def test_mesaj_distinge_env(env_db, monkeypatch):
|
||||
"""La esec de login pe test vs prod, mesajul difera ('TESTARE' vs 'PRODUCTIE').
|
||||
|
||||
US-007 AC: 'mesaj distinct creds invalide pe TESTARE vs pe PRODUCTIE'.
|
||||
Design F6/F7: banner-ul de eroare indica pe ce mediu a esuat login-ul.
|
||||
Mesaj distinct creds invalide pe TESTARE vs pe PRODUCTIE.
|
||||
Banner-ul de eroare indica pe ce mediu a esuat login-ul.
|
||||
"""
|
||||
import app.web.routes as routes_mod
|
||||
from app.config import get_settings
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste T3 — validare de domeniu prezentari (app.validation).
|
||||
"""Validare de domeniu prezentari (app.validation).
|
||||
|
||||
Un test per regula din plan.md sect. 2 / contract. Validarea normalizeaza
|
||||
(strip/upper) si intoarce erori structurate {field, message}; nu ridica exceptii.
|
||||
@@ -140,7 +140,7 @@ def test_erori_multiple_cumulate():
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# US-002: 3 niveluri — coduri stabile, forma aditiva, back-compat
|
||||
# 3 niveluri — coduri stabile, forma aditiva, back-compat
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
from app import errors as err_mod # noqa: E402
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
"""Teste US-006 (PRD 5.11): Import = container compact colapsabil.
|
||||
|
||||
TDD — testele sunt scrise INAINTE de implementare (RED), apoi devin GREEN.
|
||||
"""Import: container compact colapsabil.
|
||||
|
||||
Verifica:
|
||||
- Containerul de import e colapsat implicit cand exista trimiteri (are_trimiteri=True)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-009 (PRD 5.5): panou admin UI — selectie cu bife + master, bara de actiuni bulk
|
||||
"""Teste panou admin UI — selectie cu bife + master, bara de actiuni bulk
|
||||
(Activeaza/Blocheaza/Arhiveaza/Sterge), actiuni per-rand, fara nota 'cont dev implicit',
|
||||
grila standard.
|
||||
"""
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"""Teste PRD 5.19 strat WEB: toggle "Trimite automat la RAR" (US-004), trimitere
|
||||
manuala per rand + bulk (US-005), afisaj held (US-006 UI), banner coada tinuta
|
||||
imbatranita + contor manual (US-007), audit app_events (US-009).
|
||||
"""Strat web: toggle "Trimite automat la RAR", trimitere manuala per rand + bulk,
|
||||
afisaj held, banner coada tinuta imbatranita + contor manual, audit app_events.
|
||||
|
||||
Model: TestClient + login web (ca tests/test_web_lifecycle.py). NU atinge conftest.
|
||||
"""
|
||||
@@ -107,7 +106,7 @@ def _held(sid):
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# US-004 — toggle Auto: persistenta + CSRF + scope #
|
||||
# Toggle Auto: persistenta + CSRF + scope #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
def test_auto_send_persista(client):
|
||||
@@ -154,7 +153,7 @@ def test_auto_send_scoped_ignora_account_id_din_formular(client):
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# US-004 — auto-release OFF->ON cu garda de confirmare #
|
||||
# Auto-release OFF->ON cu garda de confirmare #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
def test_off_to_on_fara_confirmare_nu_elibereaza(client):
|
||||
@@ -196,7 +195,7 @@ def test_off_to_on_fara_randuri_tinute_comite_direct(client):
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# US-005 — trimitere manuala per rand + bulk #
|
||||
# Trimitere manuala per rand + bulk #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
def test_trimite_acum_rand_tinut(client):
|
||||
@@ -256,7 +255,7 @@ def test_trimite_toate_scoped(client):
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# US-006 (UI) — eticheta held + buton Trimite in lista #
|
||||
# Eticheta held + buton Trimite in lista #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
def test_rand_tinut_eticheta_si_buton(client):
|
||||
@@ -277,7 +276,7 @@ def test_rand_ne_tinut_fara_buton(client):
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# US-007 — banner coada tinuta imbatranita + contor manual #
|
||||
# Banner coada tinuta imbatranita + contor manual #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
def test_banner_aged_apare_pt_rand_vechi(client):
|
||||
@@ -307,7 +306,7 @@ def test_contor_manual_apare(client):
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# US-009 — audit app_events #
|
||||
# Audit app_events #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
def _events(account_id, tip):
|
||||
@@ -348,8 +347,8 @@ def test_audit_held_eliberat_bulk(client):
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# /code-review (fix findings #2/#3/#5): stickiness filtru held, banner OOB, #
|
||||
# afordanta de eliberare in panoul de detaliu. #
|
||||
# Stickiness filtru held, banner OOB, afordanta de eliberare in panoul de #
|
||||
# detaliu. #
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
def test_fragment_held_gol_nu_da_422(client):
|
||||
@@ -392,7 +391,7 @@ def test_fragment_lista_curata_reseteaza_f_held(client):
|
||||
|
||||
def test_banner_bulk_dispare_dupa_eliberare(client):
|
||||
"""Banner 'Trimite toate (N)' e OOB (#bulk-held-banner-wrap): dupa eliberarea tuturor
|
||||
randurilor tinute, wrapper-ul revine gol (fara buton) — nu mai ramane stale (#3)."""
|
||||
randurilor tinute, wrapper-ul revine gol (fara buton) — nu mai ramane stale."""
|
||||
aid = _account_user("k4@test.com")
|
||||
csrf = _login(client, "k4@test.com")
|
||||
_ins(aid, "queued", held=1)
|
||||
@@ -410,7 +409,7 @@ def test_banner_bulk_dispare_dupa_eliberare(client):
|
||||
|
||||
def test_detaliu_rand_tinut_are_buton_trimite_acum(client):
|
||||
"""Panoul de detaliu al unui rand tinut (queued AND held=1) arata eticheta manuala +
|
||||
buton 'Trimite acum la RAR' (#5)."""
|
||||
buton 'Trimite acum la RAR'."""
|
||||
aid = _account_user("k5@test.com")
|
||||
_login(client, "k5@test.com")
|
||||
sid = _ins(aid, "queued", held=1)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Teste US-011 (PRD 3.5): badge cu contoare pe tab-uri (atentionari).
|
||||
"""Badge cu contoare pe tab-uri (atentionari).
|
||||
|
||||
Badge doar cand contorul > 0; numar corect scoped pe cont; aria-label cu sens.
|
||||
"""
|
||||
@@ -74,7 +74,7 @@ def client(monkeypatch):
|
||||
|
||||
|
||||
def test_badge_mapari(client):
|
||||
"""US-009: cu operatii needs_mapping, intrarea Mapari din meniu poarta un badge cu numar."""
|
||||
"""Cu operatii needs_mapping, intrarea Mapari din meniu poarta un badge cu numar."""
|
||||
acct = _create_account_user("bm@test.com")
|
||||
_ins(acct, "needs_mapping")
|
||||
_ins(acct, "needs_mapping")
|
||||
@@ -83,7 +83,7 @@ def test_badge_mapari(client):
|
||||
resp = client.get("/")
|
||||
assert resp.status_code == 200
|
||||
html = resp.text
|
||||
# US-009: Mapari e acum in meniu (nu tab); badgeul apare in intrarea meniului
|
||||
# Mapari e in meniu (nu tab); badgeul apare in intrarea meniului
|
||||
idx = html.find('href="/?tab=mapari"')
|
||||
assert idx != -1, "Intrarea Mapari lipseste din meniu"
|
||||
# Cauta badgeul in contextul link-ului Mapari
|
||||
@@ -93,7 +93,7 @@ def test_badge_mapari(client):
|
||||
|
||||
|
||||
def test_badge_trimiteri_blocate(client):
|
||||
"""US-003 (3.6): cu randuri blocate, marcajul de atentie apare in heading-ul
|
||||
"""Cu randuri blocate, marcajul de atentie apare in heading-ul
|
||||
sectiunii 'Trimiterile tale' de pe Acasa (tab-ul Trimiteri a disparut)."""
|
||||
acct = _create_account_user("bt@test.com")
|
||||
_ins(acct, "needs_data")
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
"""TDD 5.18 US-007 — Badge sursa sugestie in editorul de mapare (_mapari.html).
|
||||
"""Badge sursa sugestie in editorul de mapare (_mapari.html).
|
||||
|
||||
Chip mic langa sugestia sistemului care arata DE UNDE vine codul propus:
|
||||
- "confirmat" -> GOLD partajat (validat de om, shared_mappings)
|
||||
- "similar" -> SILVER exact-match / k-NN embeddings (exemplu deja vazut)
|
||||
- "non-operatie" -> pre-filtru NUL determinist (ITP/plata/discount...)
|
||||
|
||||
Toate suggestion-only (#13): badge-ul e doar indiciu vizual, nu schimba enqueue.
|
||||
Suggestion-only: badge-ul e doar indiciu vizual, nu schimba enqueue.
|
||||
Render real prin GET /_fragments/mapari (fragmentul HTMX scoped pe cont).
|
||||
"""
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Teste US-010 (PRD 5.15): Bulk-fix din lista — selectie multipla -> actiune unica.
|
||||
"""Bulk-fix din lista: selectie multipla -> actiune unica.
|
||||
|
||||
Acceptance criteria:
|
||||
Cazuri:
|
||||
- test_bulk_remapeaza_selectie: N randuri needs_mapping + aplica cod -> toate -> queued
|
||||
- test_bulk_doar_blocate: randuri sent/sending nu sunt eligibile (sarite silentios)
|
||||
- test_bulk_scoped_cont: 404-before-409 — un cont nu atinge randurile altui cont
|
||||
@@ -120,11 +120,11 @@ def client(monkeypatch):
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Teste US-010
|
||||
# Teste
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_bulk_remapeaza_selectie(client):
|
||||
"""US-010 AC principal: N randuri needs_mapping + aplica cod valid -> toate -> queued.
|
||||
"""N randuri needs_mapping + aplica cod valid -> toate -> queued.
|
||||
|
||||
OE-1 face parte din nomenclatorul seed (nomenclator_seed.FALLBACK_NOMENCLATOR),
|
||||
incarcat de init_db la startup; nu e nevoie de insert separat.
|
||||
@@ -172,7 +172,7 @@ def test_bulk_remapeaza_selectie(client):
|
||||
|
||||
|
||||
def test_bulk_doar_blocate(client):
|
||||
"""US-010 AC eligibilitate: randuri sent/sending sarite silentios; doar blocate procesate."""
|
||||
"""Randuri sent/sending sarite silentios; doar blocate procesate."""
|
||||
acct = _create_account_user("bulk_fix2@test.com")
|
||||
|
||||
# Rand sent (read-only, nu trebuie atins)
|
||||
@@ -211,7 +211,7 @@ def test_bulk_doar_blocate(client):
|
||||
|
||||
|
||||
def test_bulk_scoped_cont(client):
|
||||
"""US-010 AC scope: contul A nu poate modifica randurile contului B.
|
||||
"""Contul A nu poate modifica randurile contului B.
|
||||
|
||||
Pattern 404-before-409: randurile cross-account sunt sarite silentios
|
||||
(nu confirmam existenta), raspuns HTTP 200 cu sumar care reflecta 0 reusite.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user