Files
roafacturare/docs/test_curs_bnr_headless.md
2026-09-17 22:44:24 +03:00

11 KiB

Test headless — citeste_curs_bnr (arhiva 10 zile + fisier anual BNR)

Tinta: COMUN\clase\onom_curs.vcx, clasa actualizare_curs_bnr, metoda citeste_curs_bnr (patch v3, deja scris in binar — confirmat inainte de test, vezi sectiunea 0). Metoda a fost apelata DIRECT, niciodata prin initializeaza — niciun apel la initializeaza() sau scrie_curs_bnr() in tot scriptul, deci nicio scriere in Oracle. Conexiunea Oracle deschisa de mediul de test (test_init_env_auto_roafacturare.prg) face doar SELECT-uri (firma, calendar, pack_sesiune.set*) pentru initializarea sesiunii — nimic legat de cursuri BNR.

0. Confirmare inainte de test

COMUN\clase\onom_curs.vc2 are deja proprietatile clinkan/clinkarhiva si noua citeste_curs_bnr cu parametrul tnSursa (linia 106+), identice cu blocul NOU din docs\patch_curs_bnr_arhiva.md — verificat cu grep inainte de a scrie testul. .vcx/.VCT au acelasi mtime cu .vc2 (22:11, 17.09.2026) — write-back-ul din docs\writeback_curs_bnr.md confirmat aplicat, nu s-a atins din nou.

1. Artefact de harness gasit si ocolit (NU e defect de cod)

Apeland citeste_curs_bnr direct (fara initializeaza), primul apel a agatat testul (90s timeout, 0 dialoguri detectate de watchdog_vfp.ps1). Cauza, confirmata prin proba minimala (test_curs_bnr_probe2.prg, sters dupa confirmare):

  • citeste_curs_bnr incepe cu creeaza_backup_cursoare(This.cCursor) (onom_curs.vc2:118), care cheama copiaza_structura_cursor() din COMUN\programe\oproceduri_comune.prg:3024.
  • Acolo, If Used(tcSursa) (oproceduri_comune.prg:3027) — daca ccrsbnr nu e deja deschis (cazul cand chemi metoda direct, fara sa treci prin initializeaza, care il creeaza via goExecutor.oExecute), cade pe Else si cheama amessagebox("Eroare interna 2 - copiaza structura cursor",...) (oproceduri_comune.prg:3036).
  • amessagebox (functia REALA, oproceduri_comune.prg:1205) e apelata din acelasi fisier ca copiaza_structura_cursor — mock_amessagebox.prg documenteaza explicit aceasta limita ("LIMITA 1: nu acopera sigur apelurile INTRA-FISIER") — deci mock-ul nu intercepteaza, se deschide messagebox_form real (MessageBox.vcx), modal, headless agata.
  • In productie nu se intampla: initializeaza() creeaza This.cCursor cu goExecutor.oExecute(lcSql, This.cCursor) (onom_curs.vc2:159) INAINTE de a chema citeste_curs_bnr.

Reparatia e in test, nu in cod: inainte de FIECARE apel, testul precreaza ccrsbnr gol (CREATE CURSOR ccrsbnr (Currency C(10), multiplier N(10,4), Curs N(14,6)) — campurile confirmate din scrie_curs_bnr, onom_curs.vc2:282-283, care citeste exact Currency/multiplier/Curs din cursor). Metoda oricum inchide cursorul (Use In) si il reconstruieste din raspunsul HTTP (Xmltocursor), deci structura precreata conteaza doar pentru backup, nu pentru rezultat. Confirmat cu proba minimala: dupa precreare, Return=0, Reccount=37, EUR curs=5.2637 — fara agatare. Niciun fisier de productie nu a fost atins pentru asta.

2. Rezultate — 7 cazuri cerute + 1 caz suplimentar (cascada)

# Caz Parametri Return asteptat Return obtinut Durata Rezultat
1 sursa 1, azi (zi lucratoare) dData=17.09.2026 (joi) 0 0 0.238s PASS — Reccount=37, EUR curs=5.2637
2 sursa 1, luni recenta dData=14.09.2026 (luni) 0 0 0.048s PASS — cade pe publicarea de vineri, Reccount=37, EUR curs=5.2557
3 sursa 2, martie an curent dData=15.03.2026 0 0 0.084s PASS — Reccount=37, EUR curs=5.0947
4 sursa 2, 2 ianuarie an curent dData=02.01.2026 0 0 0.202s PASS — trecere in 2025, Reccount=38, EUR curs=5.0985
5 sursa 1, data mult mai veche decat arhiva dData=01.01.2026 2 2 0.047s PASS — "data lipsa" distinct de "BNR picat"
6 sursa 1, host invalid (indisponibilitate) cLinkArhiva=host .invalid inexistent, dData=azi 1 2 0.181s FAIL — vezi sectiunea 3, defect real in cod
7 fara parametru (compatibilitate inapoi) dData=18.08.2026 0 (comportament sursa 0) 0 0.041s PASS — This.dData s-a suprascris la 18.09.2026 (publicare+1), ca inainte
8 (suplimentar, cerut de coordonator) cascada reala: acelasi obiect/dData din caz 5 (Return 2 pe sursa 1), apoi sursa 2 dData=01.01.2026 0 0 0.120s PASS — Reccount=38, EUR curs=5.0985, FARA "Eroare interna 2" la al doilea apel

Sumar: 7 PASS, 1 FAIL (cazul 6).

3. Cazul 5 — eroare tranzitorie auto-vindecata, nu afecteaza Return

La finalul cazului 5 (Return 2, data prea veche), logul a prins:

[ON ERROR] 13 Alias 'CCRSBNR' is not found. in REPUNE_BACKUP_CURSOARE linia 6363

Cauza: citeste_curs_bnr inchide This.cCursor (Use In) inainte de apelul HTTP; pe ramura Return 2 cheama repune_backup_cursoare(This.cCursor) (onom_curs.vc2:175), a carei prima linie utila e Select (tcOriginal) (oproceduri_comune.prg:6363) pe un alias deja inchis — risc preexistent, deja documentat in docs\patch_curs_bnr_arhiva.md sectiunea 5, punctul 3 ("repune_backup_cursoare pe cursor deja inchis"), nu introdus de acest patch. Confirmat acum ca se reproduce efectiv. Efect: eroarea e prinsa de ON ERROR, executia continua la linia urmatoare (lnRecno = Recno()), iar liniile de dupa (Select * From bckpccrsbnr Into Cursor ccrsbnr) reconstruiesc singure alias-ul ccrsbnr — auto-vindecare in aceeasi rulare, Return 2 final e corect si cazul 8 (cascada imediat urmatoare, sursa 2 pe acelasi obiect) confirma ca ccrsbnr ramane intr-o stare corecta (Used, fara sa mai loveasca "Eroare interna 2" la creeaza_backup_cursoare din apelul urmator). Nu s-a reparat codul — doar raportat, cum s-a cerut.

4. Cazul 6 — defect REAL, nu artefact de test

Return obtinut 2, asteptat 1. Nu e problema harnessului — e un gol real in citeste_curs_bnr pentru cazul specific "host complet nerezolvabil" (nu doar HTTP non-200 sau timeout pe conexiune).

Secventa exacta din log (prima eroare e cea reala, restul e cascada, exact ca in nota de procedura despre ON ERROR):

[ON ERROR] 1429 OLE IDispatch exception ... WinHttp.WinHttpRequest: The server name or address
could not be resolved. in ACTUALIZARE_CURS_BNR.CITESTE_CURS_BNR (linia loHTTP.Send(), onom_curs.vc2:137)
[ON ERROR] 1429 ... The data necessary to complete this operation is not yet available. (citirea
ulterioara a lui loHTTP.Status, onom_curs.vc2:139)
... (cascada: 8x eroare 11 "Function argument value, type, or count is invalid" in bucla
Do While de la onom_curs.vc2:151-173, cu lcFisier ramas needefinit)
[ON ERROR] 13 Alias 'CCRSBNR' is not found. in REPUNE_BACKUP_CURSOARE linia 6363

Explicatie: loHTTP.Send() (onom_curs.vc2:137) NU e in TRY/CATCH si NU verifica intai daca request-ul a esuat la nivel de retea/DNS — arunca direct o exceptie OLE cand hostul nu se rezolva. Fara TRY/CATCH in metoda, ON ERROR global preia eroarea si, conform semanticii VFP (executia continua la linia URMATOARE, nu la ramura Else corecta), programul "sare" peste blocul If loHTTP.Status = 200 ... Else ... Return 1 ... Endif fara sa execute nici ramura de succes, nici Return 1 — continua direct in bucla de cautare Cube cu lcFisier gol/nedefinit, epuizeaza cele 10 incercari (cascada de erori 11), si iese pe ramura "nimic gasit" -> Return 2. Rezultatul final e gresit: un host complet indisponibil (DNS esuat) e raportat ca "data lipsa" (2), nu ca "indisponibilitate" (1) — exact confuzia pe care patch-ul trebuia sa o elimine, dar doar pentru raspunsuri HTTP non-200 de la un server care RASPUNDE, nu pentru esecul de rezolvare DNS.

Durata: 0.181s — nu agata deloc (departe de cele 5s/5s/5s/15s din SetTimeouts); esecul de rezolvare DNS e instant, nu trece prin timeout-uri.

Conform instructiunii explicite: nu am reparat codul. Raportez cu dovada de mai sus.

5. Cum s-a rulat

Script: D:\ROA\ROAFACTURARE\COMUN\utile\Teste\test_curs_bnr_headless.prg (helper-e proprii: crea_cursor_gol, log_txt, log_eroare, verifica_caz — toate in acelasi fisier).

Precompilare izolata:

powershell -ExecutionPolicy Bypass -File D:\ROA\ROAFACTURARE\COMUN\utile\Teste\_precompile.ps1 -Prg D:\ROA\ROAFACTURARE\COMUN\utile\Teste\test_curs_bnr_headless.prg

Rulare (proces separat, timeout 240s, in PowerShell):

$p = Start-Process -FilePath 'C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe' `
  -ArgumentList '-A','-T','"D:\ROA\ROAFACTURARE\COMUN\utile\Teste\test_curs_bnr_headless.prg"' -PassThru
if (-not $p.WaitForExit(240000)) { $p.Kill() }

Log complet (marca unica de rulare in prima linie, SYS(2015)): D:\ROA\ROAFACTURARE\COMUN\utile\Teste\_test_curs_bnr_out.txt — ultima rulare confirmata: mtime 17.09.2026 22:26, marca _7KA1C340N.

Retea: toate cele 8 sub-cazuri au ajuns efectiv la curs.bnr.ro (sau la hostul invalid pentru cazul 6) — reteaua a functionat, niciun rezultat nu e raportat fals din lipsa de conectivitate.

6. Confirmare: nicio scriere in Oracle

Scriptul apeleaza EXCLUSIV loCurs.citeste_curs_bnr(...) pe obiecte actualizare_curs_bnr instantiate direct — niciun apel la initializeaza() (care ar citi din Oracle si, la Reccount=0, ar declansa cascada de UI) si niciun apel la scrie_curs_bnr() (singura metoda a clasei care scrie in pack_curs.scrie_cotatii_curs). Singurele interactiuni cu Oracle din intreaga rulare sunt cele din test_init_env_auto_roafacturare.prg (conectare + SELECT-uri de sesiune), neschimbate fata de orice alt test headless din acest proiect.

7. Fisiere temporare de test, sterse dupa confirmare

test_curs_bnr_probe.prg / .fxp si test_curs_bnr_probe2.prg / .fxp (folosite doar pentru diagnostic, sterse din COMUN\utile\Teste\ dupa ce artefactul de harness a fost confirmat si reparat in scriptul final). Raman pe disc doar test_curs_bnr_headless.prg / .fxp si logul _test_curs_bnr_out.txt.

8. Rerulare dupa reparatia Try/Catch (v4)

Data/ora: 17.09.2026 22:36. Reparatia din docs\patch_curs_bnr_arhiva.md sectiunea 7 (Try/Catch in jurul ambelor loHTTP.Send() din citeste_curs_bnr) e scrisa in binar (write-back confirmat, fidelity-check pe round-trip identic). .FXP vechi al testului sters, precompilat din nou, o singura rulare vfp9 (-A -T), log nou confirmat pe mtime si marca (_7KA1CGZRZ, 22:36:54).

# Caz Return inainte (sectiunea 2) Return dupa Rezultat
1-4, 7, 8 neschimbate 0 0 PASS (neschimbat)
5 data mult mai veche decat arhiva 2 2 PASS (neschimbat)
6 host invalid (indisponibilitate) 2 (FAIL, asteptat 1) 1 PASS

Sumar nou: 8 PASS, 0 FAIL (fata de 7 PASS, 1 FAIL inainte de reparatie). Nicio regresie pe cazurile 1-5, 7, 8. Cazul 6 intoarce acum 1 ("BNR picat") in loc de 2 ("data lipsa"), deci initializeaza ofera acum linkul https://www.cursbnr.ro/ in loc de mesajul gresit "Nu exista cursul BNR pentru data specificata!".