Files
rar-autopass/tests/test_worker_held.py
Claude Agent eade702a52 fix(5.19): corectii UX/retentie held (findings #2-#6 /code-review high)
#2 Filtrul "doar tinute" (held=1) devine persistent: hidden #f-held in
   #filtre-trimiteri sincronizat prin OOB din _submissions.html + paginare
   pastreaza held=1; chip "Doar tinute manual / Arata tot" ca off-switch.
   Param `held` schimbat la str (held= gol nu mai da 422 la coercion).
#3 Banner bulk "Trimite toate (N)" extras in _bulk_held_banner.html si
   re-randat prin OOB (#bulk-held-banner-wrap) la fiecare reincarcare a listei
   -> nu mai ramane stale dupa eliberari (count revine la 0).
#4 tools/carantina_held seteaza purge_after (blocked_retention_days) pe randurile
   carantinate -> PII nu mai sta la nesfarsit (purge_expired le poate sterge).
#5 Panoul de detaliu marcheaza randul tinut (eticheta amber) si ofera buton
   "Trimite acum la RAR" (paritate cu randul din lista).
#6 expire_held seteaza purge_after=now-1s -> randul expirat e purjabil in ACELASI
   ciclu (purge_expired foloseste comparatie stricta), nu la ciclul urmator.

Teste noi: stickiness held + banner OOB + detaliu buton (test_web_auto_send),
purge_after carantina, purge acelasi-ciclu (test_worker_held). 1541 passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 11:19:00 +00:00

198 lines
6.9 KiB
Python

"""Teste PRD 5.19 US-003 + US-008 — worker respecta flag `held`.
US-003: claim_one sare peste randurile `queued AND held=1` (tinute manual).
US-008: expire_held expira randurile tinute mai vechi de `held_retention_days`
(default 90) -> status 'error', rar_error='TINUT_EXPIRAT', purge_after
DIRECT la momentul expirarii (NU +30z retentie blocati -> nu 120z total),
apoi purge_expired le sterge (PII purjat).
TDD: testele se scriu INAINTE de modificarea worker-ului.
"""
from __future__ import annotations
import json
import os
import tempfile
import pytest
# --- Fixture DB (pattern din test_worker_active_gate.py) ---
@pytest.fixture()
def env(monkeypatch):
tmp = tempfile.mkdtemp()
monkeypatch.setenv("AUTOPASS_DB_PATH", os.path.join(tmp, "t.db"))
from app.config import get_settings
get_settings.cache_clear()
from app.db import get_connection, init_db
init_db()
conn = get_connection()
yield conn, get_settings()
conn.close()
get_settings.cache_clear()
# --- Helpers ---
_CONTENT = {
"vin": "WVWZZZ1KZAW000123", "nr_inmatriculare": "B999TST",
"data_prestatie": "2026-06-15", "odometru_final": "123456",
"prestatii": [{"cod_prestatie": "OE-1"}], "sistem_reparat": "null",
}
def _insert(conn, account_id=None, status="queued", held=0, content=None, created_at=None):
content = content or _CONTENT
cur = conn.execute(
"INSERT INTO submissions (idempotency_key, status, payload_json, account_id, held) "
"VALUES (?, ?, ?, ?, ?)",
(f"key-{os.urandom(4).hex()}", status, json.dumps(content), account_id, held),
)
sid = int(cur.lastrowid)
if created_at is not None:
conn.execute("UPDATE submissions SET created_at=? WHERE id=?", (created_at, sid))
return sid
def _row(conn, sid):
return conn.execute("SELECT * FROM submissions WHERE id=?", (sid,)).fetchone()
def _row_status(conn, sid):
r = _row(conn, sid)
return r["status"] if r else None
# --- US-003: claim_one sare peste randurile tinute ---
def test_claim_sare_rand_tinut(env):
"""queued, held=1, cont activ, send on -> claim_one intoarce None; ramane queued."""
from app.accounts import create_account
from app.worker.__main__ import claim_one
conn, _ = env
acct_id = create_account(conn, "Service Tinut", active=True)
sid = _insert(conn, account_id=acct_id, held=1)
result = claim_one(conn)
assert result is None, "claim_one trebuia sa sara peste randul tinut (held=1)"
assert _row_status(conn, sid) == "queued", "randul tinut trebuia sa ramana queued"
def test_claim_ia_rand_neted(env):
"""Acelasi rand cu held=0 -> claim_one il ia si il marcheaza sending."""
from app.accounts import create_account
from app.worker.__main__ import claim_one
conn, _ = env
acct_id = create_account(conn, "Service Liber", active=True)
sid = _insert(conn, account_id=acct_id, held=0)
result = claim_one(conn)
assert result is not None, "claim_one trebuia sa ridice randul held=0"
assert result["id"] == sid
assert _row_status(conn, sid) == "sending"
def test_eliberarea_deblocheaza_claim(env):
"""held=1 -> claim_one None; dupa held=0 -> claim_one il ridica."""
from app.accounts import create_account
from app.worker.__main__ import claim_one
conn, _ = env
acct_id = create_account(conn, "Service Eliberat", active=True)
sid = _insert(conn, account_id=acct_id, held=1)
assert claim_one(conn) is None
assert _row_status(conn, sid) == "queued"
conn.execute("UPDATE submissions SET held=0 WHERE id=?", (sid,))
result = claim_one(conn)
assert result is not None and result["id"] == sid
assert _row_status(conn, sid) == "sending"
# --- US-008: expirare randuri tinute ---
def test_expire_held_expira_rand_vechi(env):
"""queued, held=1, created_at vechi (>90z) -> error + TINUT_EXPIRAT + purge_after ~now."""
from app.accounts import create_account
from app.worker.__main__ import expire_held
conn, settings = env
acct_id = create_account(conn, "Service Vechi", active=True)
sid = _insert(conn, account_id=acct_id, held=1,
created_at="datetime('now','-100 days')")
# created_at trebuie sa fie o valoare literala, nu expresie SQL text -> setam explicit.
conn.execute("UPDATE submissions SET created_at=datetime('now','-100 days') WHERE id=?", (sid,))
n = expire_held(conn, settings)
assert n == 1, "expire_held trebuia sa expire exact 1 rand"
row = _row(conn, sid)
assert row["status"] == "error"
assert row["rar_error"] == "TINUT_EXPIRAT"
assert row["purge_after"] is not None
# purge_after ~ now (NU +30z): verificam ca e <= acum + o mica marja (sub 1 zi).
aproape_acum = conn.execute(
"SELECT purge_after <= datetime('now', '+1 day') AS ok FROM submissions WHERE id=?",
(sid,),
).fetchone()["ok"]
assert aproape_acum == 1, "purge_after trebuia setat ~now, nu +30z"
assert row["sending_since"] is None
def test_expire_held_ignora_rand_recent(env):
"""queued, held=1 recent (created_at now) -> neatins de expire_held."""
from app.accounts import create_account
from app.worker.__main__ import expire_held
conn, settings = env
acct_id = create_account(conn, "Service Recent", active=True)
sid = _insert(conn, account_id=acct_id, held=1)
n = expire_held(conn, settings)
assert n == 0
assert _row_status(conn, sid) == "queued"
def test_expire_held_ignora_rand_neted_vechi(env):
"""queued, held=0, vechi -> NU e tinut -> neatins de expire_held."""
from app.accounts import create_account
from app.worker.__main__ import expire_held
conn, settings = env
acct_id = create_account(conn, "Service NetedVechi", active=True)
sid = _insert(conn, account_id=acct_id, held=0)
conn.execute("UPDATE submissions SET created_at=datetime('now','-100 days') WHERE id=?", (sid,))
n = expire_held(conn, settings)
assert n == 0
assert _row_status(conn, sid) == "queued"
def test_expire_held_apoi_purge_sterge_randul(env):
"""Lant complet ACELASI CICLU: expire_held (purge_after=now-1s) -> purge_expired
sterge randul imediat (PII purjat), fara sa astepte ciclul urmator (fix /code-review #6)."""
from app.accounts import create_account
from app.worker.__main__ import expire_held, purge_expired
conn, settings = env
acct_id = create_account(conn, "Service Purjat", active=True)
sid = _insert(conn, account_id=acct_id, held=1)
conn.execute("UPDATE submissions SET created_at=datetime('now','-100 days') WHERE id=?", (sid,))
assert expire_held(conn, settings) == 1
# expire_held seteaza purge_after=now-1s -> purge_expired (purge_after < now strict) il
# sterge in ACELASI ciclu, fara nudge manual de timp.
stats = purge_expired(conn)
assert stats["submissions_purged"] >= 1
assert _row(conn, sid) is None, "randul expirat trebuia sters de purge_expired in acelasi ciclu"