171 lines
11 KiB
Markdown
171 lines
11 KiB
Markdown
# 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):
|
|
```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!".
|