test(service-auto): unit tests multi-tenant + lookup + partener + pc_nr
Acoperire 49 tests offline (fără Oracle real): test_comanda_helpers (16): _build_pc_nr toate prefixele VFP + fallback, _build_sir_id_operatii csv + limit 4000 chars, _PREFIX_MAP regression. test_router_authorization (9): _company_id fallback JWT companies[0], 403 firmă neautorizată, 400 companies[] gol, string→int coercion; _server_id extragere din request.state. test_lookup_endpoints (15): cache hit/miss per schema pentru tip_deviz, masini, asiguratori, inspectori (per-asig), operatii; LIKE escape %/_/\; min 2 chars short-circuit; server_id propagat la get_connection. test_partener_create (9): 5 Pydantic validation (denumire min 2, id_firma ge 1, cui opțional), 4 service mocked (happy path, 409 duplicat CUI, fără CUI, lipsă GRANT → 500 log.critical). Pattern mock Oracle: fake context managers (async get_connection + sync cursor), monkeypatch pe lookup_service.get_schema (not _context, din cauza binding copy la import). Rulare: pytest backend/modules/service_auto/tests/ -q → 62 passed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
197
backend/modules/service_auto/tests/test_partener_create.py
Normal file
197
backend/modules/service_auto/tests/test_partener_create.py
Normal file
@@ -0,0 +1,197 @@
|
||||
"""
|
||||
Unit tests pentru creare partener nou:
|
||||
- Validare PartnerCreateRequest (denumire min_length=2, id_firma ge=1)
|
||||
- LookupService.create_partener — happy path + duplicat CUI (409) + lipsă GRANT (500)
|
||||
|
||||
Folosește mock pentru oracle_pool și _context.get_schema (fără DB).
|
||||
"""
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import oracledb
|
||||
import pytest
|
||||
from fastapi import HTTPException
|
||||
from pydantic import ValidationError
|
||||
|
||||
from backend.modules.service_auto.schemas.comanda import PartnerCreateRequest
|
||||
from backend.modules.service_auto.services.lookup_service import LookupService
|
||||
|
||||
|
||||
# ---- PartnerCreateRequest validation ----
|
||||
|
||||
def test_partner_request_denumire_too_short_raises():
|
||||
"""denumire cu 1 caracter → ValidationError (min_length=2)."""
|
||||
with pytest.raises(ValidationError) as exc:
|
||||
PartnerCreateRequest(denumire="X", id_firma=167)
|
||||
assert "denumire" in str(exc.value).lower()
|
||||
|
||||
|
||||
def test_partner_request_denumire_empty_raises():
|
||||
"""denumire goală → ValidationError."""
|
||||
with pytest.raises(ValidationError):
|
||||
PartnerCreateRequest(denumire="", id_firma=167)
|
||||
|
||||
|
||||
def test_partner_request_minimal_valid():
|
||||
"""Doar denumire + id_firma → CUI și adresa optionale = None."""
|
||||
req = PartnerCreateRequest(denumire="ACME SRL", id_firma=167)
|
||||
assert req.denumire == "ACME SRL"
|
||||
assert req.cui is None
|
||||
assert req.adresa is None
|
||||
assert req.id_firma == 167
|
||||
|
||||
|
||||
def test_partner_request_full():
|
||||
req = PartnerCreateRequest(
|
||||
denumire="ACME SRL",
|
||||
cui="RO12345678",
|
||||
adresa="Str. Exemplu nr. 1, București",
|
||||
id_firma=167,
|
||||
)
|
||||
assert req.cui == "RO12345678"
|
||||
assert req.adresa is not None and req.adresa.startswith("Str.")
|
||||
|
||||
|
||||
def test_partner_request_id_firma_zero_raises():
|
||||
"""id_firma=0 → ValidationError (ge=1)."""
|
||||
with pytest.raises(ValidationError):
|
||||
PartnerCreateRequest(denumire="ACME", id_firma=0)
|
||||
|
||||
|
||||
# ---- LookupService.create_partener (mocked) ----
|
||||
|
||||
def _make_pool_ctx(cursor_mock):
|
||||
"""
|
||||
Construiește un context manager async pentru oracle_pool.get_connection.
|
||||
Returnează: pool_mock cu .get_connection() → async ctx → conn cu .cursor()
|
||||
sync ctx care returnează cursor_mock.
|
||||
"""
|
||||
conn_mock = MagicMock()
|
||||
conn_mock.cursor.return_value.__enter__.return_value = cursor_mock
|
||||
conn_mock.cursor.return_value.__exit__.return_value = None
|
||||
conn_mock.commit = MagicMock()
|
||||
|
||||
async_ctx = MagicMock()
|
||||
async_ctx.__aenter__ = AsyncMock(return_value=conn_mock)
|
||||
async_ctx.__aexit__ = AsyncMock(return_value=None)
|
||||
|
||||
pool_mock = MagicMock()
|
||||
pool_mock.get_connection = MagicMock(return_value=async_ctx)
|
||||
return pool_mock, conn_mock
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_partener_happy_path():
|
||||
"""
|
||||
Cazul nominal:
|
||||
- Pre-check CUI: nicio coliziune (fetchone() → None)
|
||||
- SELECT MAX(id_part)+1 → 4242
|
||||
- INSERT reușește; conn.commit() apelat; întoarce PartenerItem.
|
||||
"""
|
||||
cursor = MagicMock()
|
||||
# fetchone secvență: pre-check CUI (None), SELECT MAX (4242,)
|
||||
cursor.fetchone.side_effect = [None, (4242,)]
|
||||
cursor.execute = MagicMock()
|
||||
|
||||
pool_mock, conn_mock = _make_pool_ctx(cursor)
|
||||
|
||||
with patch(
|
||||
"backend.modules.service_auto.services.lookup_service.oracle_pool",
|
||||
pool_mock,
|
||||
), patch(
|
||||
"backend.modules.service_auto.services.lookup_service.get_schema",
|
||||
new=AsyncMock(return_value="MARIUSM_AUTO"),
|
||||
):
|
||||
req = PartnerCreateRequest(
|
||||
denumire="ACME SRL", cui="RO12345678", adresa="Str. X", id_firma=167,
|
||||
)
|
||||
result = await LookupService.create_partener(req, server_id="mariusm_test")
|
||||
|
||||
assert result.id_part == 4242
|
||||
assert result.denumire == "ACME SRL"
|
||||
conn_mock.commit.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_partener_duplicate_cui_raises_409():
|
||||
"""Pre-check CUI găsește rând existent → HTTPException 409, NU INSERT."""
|
||||
cursor = MagicMock()
|
||||
cursor.fetchone.return_value = (1,) # CUI deja există
|
||||
cursor.execute = MagicMock()
|
||||
|
||||
pool_mock, conn_mock = _make_pool_ctx(cursor)
|
||||
|
||||
with patch(
|
||||
"backend.modules.service_auto.services.lookup_service.oracle_pool",
|
||||
pool_mock,
|
||||
), patch(
|
||||
"backend.modules.service_auto.services.lookup_service.get_schema",
|
||||
new=AsyncMock(return_value="MARIUSM_AUTO"),
|
||||
):
|
||||
req = PartnerCreateRequest(
|
||||
denumire="ACME SRL", cui="RO12345678", id_firma=167,
|
||||
)
|
||||
with pytest.raises(HTTPException) as exc:
|
||||
await LookupService.create_partener(req, server_id="mariusm_test")
|
||||
|
||||
assert exc.value.status_code == 409
|
||||
assert "CUI" in exc.value.detail
|
||||
conn_mock.commit.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_partener_no_cui_skips_precheck():
|
||||
"""Fără CUI → pre-check sărit, doar SELECT MAX + INSERT."""
|
||||
cursor = MagicMock()
|
||||
cursor.fetchone.side_effect = [(99,)] # doar SELECT MAX
|
||||
cursor.execute = MagicMock()
|
||||
|
||||
pool_mock, conn_mock = _make_pool_ctx(cursor)
|
||||
|
||||
with patch(
|
||||
"backend.modules.service_auto.services.lookup_service.oracle_pool",
|
||||
pool_mock,
|
||||
), patch(
|
||||
"backend.modules.service_auto.services.lookup_service.get_schema",
|
||||
new=AsyncMock(return_value="MARIUSM_AUTO"),
|
||||
):
|
||||
req = PartnerCreateRequest(denumire="Persoană fizică", id_firma=167)
|
||||
result = await LookupService.create_partener(req, server_id=None)
|
||||
|
||||
assert result.id_part == 99
|
||||
conn_mock.commit.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_partener_missing_grant_raises_500():
|
||||
"""ORA-01031 (lipsă INSERT privilege) → HTTPException 500 cu mesaj clar."""
|
||||
cursor = MagicMock()
|
||||
# CUI furnizat → fetchone secvență: pre-check (None=fără duplicat), SELECT MAX (1,)
|
||||
cursor.fetchone.side_effect = [None, (1,)]
|
||||
# INSERT primește ORA-01031
|
||||
err = oracledb.DatabaseError()
|
||||
err.args = (MagicMock(code=1031, message="ORA-01031: insufficient privileges"),)
|
||||
|
||||
def execute_side_effect(sql, *args, **kw):
|
||||
del args, kw
|
||||
if "INSERT" in sql.upper():
|
||||
raise err
|
||||
cursor.execute.side_effect = execute_side_effect
|
||||
|
||||
pool_mock, conn_mock = _make_pool_ctx(cursor)
|
||||
|
||||
with patch(
|
||||
"backend.modules.service_auto.services.lookup_service.oracle_pool",
|
||||
pool_mock,
|
||||
), patch(
|
||||
"backend.modules.service_auto.services.lookup_service.get_schema",
|
||||
new=AsyncMock(return_value="MARIUSM_AUTO"),
|
||||
):
|
||||
req = PartnerCreateRequest(
|
||||
denumire="ACME SRL", cui="RO99999999", id_firma=167,
|
||||
)
|
||||
with pytest.raises(HTTPException) as exc:
|
||||
await LookupService.create_partener(req, server_id="mariusm_test")
|
||||
|
||||
assert exc.value.status_code == 500
|
||||
assert "privilegii" in exc.value.detail.lower()
|
||||
conn_mock.commit.assert_not_called()
|
||||
Reference in New Issue
Block a user