""" 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()