Backend: - service_auto module complet: router, service, schemas, 5 teste suites (22/22 passed) - 5 endpoints: GET /ping, /firme, /tip-deviz, /masini, POST /comenzi - SP_CREEAZA_COMANDA_PROTOTIP creat în MARIUSM_AUTO (VALID, 5.9ms) - oracle_pool.py: session_callback backward-compat patch - ROA_WEB user: grants SP-only confirmate (H3), mariusm_test pool switchat - pyproject.toml: integration pytest marker înregistrat Frontend: - ComandaNoua.vue: date reale din Oracle (firme/tip-deviz/masini), nu hardcodate - src/modules/service-auto/services/api.js: axios service cu Bearer token - src/router/index.js: rută /service-auto/comanda-noua Docs: - decision-log.md: verdict MERGE, toate 6 ipoteze CONFIRMED - learnings.md: 7 patterns reutilizabile - grants-audit.md: arhitectura multi-tenant + proxy auth analysis + V_NOM_FIRME loop - template-modul-oracle.md: rețetă completă pentru module Oracle noi - TODO-phase2.md: 7 items concrete Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
98 lines
3.8 KiB
Python
98 lines
3.8 KiB
Python
"""
|
|
Unit tests — Oracle error code → HTTP status mapping.
|
|
|
|
Tests _handle_oracle_error() directly. No live Oracle connection required.
|
|
|
|
Covered mappings:
|
|
ORA-20001 … ORA-20999 → HTTP 422 (business errors from RAISE_APPLICATION_ERROR)
|
|
ORA-12541/12170/12154/12560 → HTTP 503 (Oracle network / TNS unreachable)
|
|
ORA-01017 → HTTP 500 (bad credentials)
|
|
ORA-00942 → HTTP 500 (missing object / grant)
|
|
ORA-<other> → HTTP 500 (unexpected error)
|
|
"""
|
|
import pytest
|
|
from unittest.mock import MagicMock
|
|
from fastapi import HTTPException
|
|
|
|
from backend.modules.service_auto.services.comanda_service import _handle_oracle_error
|
|
|
|
|
|
def _make_oracle_error(code: int, msg: str = "test error"):
|
|
"""
|
|
Build a minimal mock that mimics oracledb.DatabaseError structure.
|
|
_handle_oracle_error only accesses e.args[0].code and e.args[0].message,
|
|
so a MagicMock is sufficient — no live oracledb import needed.
|
|
"""
|
|
err_obj = MagicMock()
|
|
err_obj.code = code
|
|
err_obj.message = f"ORA-{code:05d}: {msg}"
|
|
exc = MagicMock()
|
|
exc.args = (err_obj,)
|
|
return exc
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Parametrised: code → expected HTTP status + fragment in detail
|
|
# ---------------------------------------------------------------------------
|
|
@pytest.mark.parametrize("code, status, detail_fragment", [
|
|
# Business errors — RAISE_APPLICATION_ERROR range
|
|
(20001, 422, "mesaj business 20001"),
|
|
(20500, 422, "mesaj business 20500"),
|
|
(20999, 422, "mesaj business 20999"),
|
|
# Oracle network / TNS unreachable
|
|
(12541, 503, "indisponibil"),
|
|
(12170, 503, "indisponibil"),
|
|
(12154, 503, "indisponibil"),
|
|
(12560, 503, "indisponibil"),
|
|
# Credential / config errors
|
|
(1017, 500, "configurare"),
|
|
# Missing object / grant
|
|
(942, 500, "internă"),
|
|
# Catch-all unexpected errors
|
|
(4031, 500, "neașteptată"), # ORA-04031: unable to allocate memory
|
|
(600, 500, "neașteptată"), # ORA-00600: internal error
|
|
])
|
|
def test_error_mapping(code, status, detail_fragment):
|
|
msg = f"mesaj business {code}" if 20001 <= code <= 20999 else "test error"
|
|
exc = _make_oracle_error(code, msg)
|
|
|
|
with pytest.raises(HTTPException) as exc_info:
|
|
_handle_oracle_error(exc)
|
|
|
|
http_exc = exc_info.value
|
|
assert http_exc.status_code == status, (
|
|
f"ORA-{code:05d} → expected HTTP {status}, got {http_exc.status_code}"
|
|
)
|
|
assert detail_fragment in http_exc.detail, (
|
|
f"ORA-{code:05d} detail: expected '{detail_fragment}' in '{http_exc.detail}'"
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ORA-20xxx: verify ORA prefix is stripped from business message
|
|
# ---------------------------------------------------------------------------
|
|
def test_20001_strips_ora_prefix():
|
|
"""The 422 detail must not contain the 'ORA-20001:' prefix."""
|
|
exc = _make_oracle_error(20001, "Mai exista o comanda cu numarul P01-42")
|
|
with pytest.raises(HTTPException) as exc_info:
|
|
_handle_oracle_error(exc)
|
|
detail = exc_info.value.detail
|
|
assert not detail.startswith("ORA-"), (
|
|
f"ORA prefix not stripped: '{detail}'"
|
|
)
|
|
assert "Mai exista" in detail
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Edge case: missing code attribute (e.g. thin-mode edge case)
|
|
# ---------------------------------------------------------------------------
|
|
def test_no_code_attribute_maps_to_500():
|
|
"""If the error object has no .code, fall through to generic 500."""
|
|
err_obj = MagicMock(spec=[]) # spec=[] means NO attributes
|
|
exc = MagicMock()
|
|
exc.args = (err_obj,)
|
|
|
|
with pytest.raises(HTTPException) as exc_info:
|
|
_handle_oracle_error(exc)
|
|
assert exc_info.value.status_code == 500
|