""" Oracle Integration Tests for GoMag Import Manager (pytest-compatible) ===================================================================== Requires Oracle connectivity and valid .env configuration. Converted from api/test_integration.py. Run: pytest api/tests/test_integration.py -v """ import os import sys import pytest # --- Marker: all tests require Oracle --- pytestmark = pytest.mark.oracle # Set working directory to project root so relative paths in .env work _script_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..") _project_root = os.path.dirname(_script_dir) # Load .env from api/ before importing app modules from dotenv import load_dotenv _env_path = os.path.join(_script_dir, ".env") load_dotenv(_env_path, override=True) # TNS_ADMIN must point to the directory containing tnsnames.ora, not the file _tns_admin = os.environ.get("TNS_ADMIN", "") if _tns_admin and os.path.isfile(_tns_admin): os.environ["TNS_ADMIN"] = os.path.dirname(_tns_admin) elif not _tns_admin: os.environ["TNS_ADMIN"] = _script_dir # Add api/ to path so app package is importable if _script_dir not in sys.path: sys.path.insert(0, _script_dir) @pytest.fixture(scope="module") def client(): """Create a TestClient with Oracle lifespan. Re-apply .env here because other test modules (test_requirements.py) may have set ORACLE_DSN=dummy at import time during pytest collection. """ # Re-load .env to override any dummy values from other test modules load_dotenv(_env_path, override=True) _tns = os.environ.get("TNS_ADMIN", "") if _tns and os.path.isfile(_tns): os.environ["TNS_ADMIN"] = os.path.dirname(_tns) elif not _tns: os.environ["TNS_ADMIN"] = _script_dir # Force-update the cached settings singleton with correct values from .env from app.config import settings settings.ORACLE_USER = os.environ.get("ORACLE_USER", "MARIUSM_AUTO") settings.ORACLE_PASSWORD = os.environ.get("ORACLE_PASSWORD", "ROMFASTSOFT") settings.ORACLE_DSN = os.environ.get("ORACLE_DSN", "ROA_CENTRAL") settings.TNS_ADMIN = os.environ.get("TNS_ADMIN", _script_dir) settings.FORCE_THIN_MODE = os.environ.get("FORCE_THIN_MODE", "") == "true" from fastapi.testclient import TestClient from app.main import app with TestClient(app) as c: yield c # --------------------------------------------------------------------------- # Test A: GET /health — Oracle must show as connected # --------------------------------------------------------------------------- def test_health_oracle_connected(client): resp = client.get("/health") assert resp.status_code == 200 body = resp.json() assert body.get("oracle") == "ok", f"oracle={body.get('oracle')!r}" assert body.get("sqlite") == "ok", f"sqlite={body.get('sqlite')!r}" # --------------------------------------------------------------------------- # Test B: Mappings CRUD cycle (uses real CODMAT from Oracle nomenclator) # --------------------------------------------------------------------------- TEST_SKU = "PYTEST_INTEG_SKU_001" @pytest.fixture(scope="module") def real_codmat(client): """Find a real CODMAT from Oracle nomenclator to use in mappings tests.""" resp = client.get("/api/articles/search", params={"q": "A"}) if resp.status_code != 200: pytest.skip("Articles search unavailable") results = resp.json().get("results", []) if not results: pytest.skip("No articles found in Oracle for CRUD test") return results[0]["codmat"] def test_mappings_create(client, real_codmat): resp = client.post("/api/mappings", json={ "sku": TEST_SKU, "codmat": real_codmat, "cantitate_roa": 2.5, }) assert resp.status_code == 200 body = resp.json() assert body.get("success") is True, f"create returned: {body}" def test_mappings_list_after_create(client, real_codmat): resp = client.get("/api/mappings", params={"search": TEST_SKU}) assert resp.status_code == 200 body = resp.json() mappings = body.get("mappings", []) found = any( m["sku"] == TEST_SKU and m["codmat"] == real_codmat for m in mappings ) assert found, f"mapping not found in list; got {mappings}" def test_mappings_update(client, real_codmat): resp = client.put(f"/api/mappings/{TEST_SKU}/{real_codmat}", json={ "cantitate_roa": 3.0, }) assert resp.status_code == 200 body = resp.json() assert body.get("success") is True, f"update returned: {body}" def test_mappings_delete(client, real_codmat): resp = client.delete(f"/api/mappings/{TEST_SKU}/{real_codmat}") assert resp.status_code == 200 body = resp.json() assert body.get("success") is True, f"delete returned: {body}" def test_mappings_verify_soft_deleted(client, real_codmat): resp = client.get("/api/mappings", params={"search": TEST_SKU, "show_deleted": "true"}) assert resp.status_code == 200 body = resp.json() mappings = body.get("mappings", []) deleted = any( m["sku"] == TEST_SKU and m["codmat"] == real_codmat and m.get("sters") == 1 for m in mappings ) assert deleted, ( f"expected sters=1 for deleted mapping, got: " f"{[m for m in mappings if m['sku'] == TEST_SKU]}" ) # --------------------------------------------------------------------------- # Test C: GET /api/articles/search # --------------------------------------------------------------------------- def test_articles_search(client): search_terms = ["01", "A", "PH"] found_results = False for term in search_terms: resp = client.get("/api/articles/search", params={"q": term}) assert resp.status_code == 200 body = resp.json() results_list = body.get("results", []) if results_list: found_results = True break assert found_results, f"all search terms {search_terms} returned empty results" # --------------------------------------------------------------------------- # Test D: POST /api/validate/scan # --------------------------------------------------------------------------- def test_validate_scan(client): resp = client.post("/api/validate/scan") assert resp.status_code == 200 body = resp.json() has_shape = "json_files" in body and ("orders" in body or "total_orders" in body) assert has_shape, f"unexpected response shape: {list(body.keys())}" # --------------------------------------------------------------------------- # Test E: GET /api/sync/history # --------------------------------------------------------------------------- def test_sync_history(client): resp = client.get("/api/sync/history") assert resp.status_code == 200 body = resp.json() assert "runs" in body, f"missing 'runs' key; got keys: {list(body.keys())}" assert isinstance(body["runs"], list) assert "total" in body