From 06f56ffe7f63d7e24fb69b4b55ab5636c71cd489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Romero=20=20=20=20=20-=F0=9D=94=87=F0=9D=94=A2?= =?UTF-8?q?=F0=9D=94=A2=F0=9D=94=AD=E2=84=9C=F0=9D=94=9E=F0=9D=94=B1?= Date: Thu, 26 Feb 2026 15:28:24 -0300 Subject: [PATCH 1/4] fix: remove V1 test_api.py (api/ module no longer exists) The V1 api/ directory was removed during V2 migration. test_api_v2.py (52 tests) covers the V2 API. --- tests/test_api.py | 506 ---------------------------------------------- 1 file changed, 506 deletions(-) delete mode 100644 tests/test_api.py diff --git a/tests/test_api.py b/tests/test_api.py deleted file mode 100644 index 139a384..0000000 --- a/tests/test_api.py +++ /dev/null @@ -1,506 +0,0 @@ -""" -Tests para MedeX API REST -========================= -Tests unitarios y de integración para la API FastAPI. -""" - -import pytest -from fastapi.testclient import TestClient - -# Import with try/except for standalone testing -try: - from api.auth import DEMO_API_KEY, _hash_key, validate_api_key - from api.main import API_VERSION, app - from api.models import Language, ResponseStatus, UrgencyLevel, UserType - from api.services import get_ddx_service, get_kb_service, get_query_service -except ImportError: - import sys - from pathlib import Path - - sys.path.insert(0, str(Path(__file__).parent.parent)) - from api.auth import DEMO_API_KEY, _hash_key, validate_api_key - from api.main import API_VERSION, app - from api.models import Language, ResponseStatus, UrgencyLevel, UserType - from api.services import get_ddx_service, get_kb_service, get_query_service - - -# ============================================================================= -# FIXTURES -# ============================================================================= - - -@pytest.fixture -def client(): - """Create test client with exception handling disabled""" - return TestClient(app, raise_server_exceptions=False) - - -@pytest.fixture -def auth_headers(): - """Headers with valid API key""" - return {"X-API-Key": DEMO_API_KEY} - - -@pytest.fixture -def invalid_auth_headers(): - """Headers with invalid API key""" - return {"X-API-Key": "invalid-key-12345"} - - -# ============================================================================= -# AUTH TESTS -# ============================================================================= - - -class TestAuthentication: - """Tests for API authentication""" - - def test_demo_key_exists(self): - """Verify demo key is defined""" - assert DEMO_API_KEY is not None - assert len(DEMO_API_KEY) > 10 - - def test_validate_valid_key(self): - """Validate demo API key""" - result = validate_api_key(DEMO_API_KEY) - assert result is not None - assert "permissions" in result - assert "query" in result["permissions"] - - def test_validate_invalid_key(self): - """Validate invalid key returns None""" - result = validate_api_key("invalid-key-12345") - assert result is None - - def test_validate_empty_key(self): - """Validate empty key returns None""" - result = validate_api_key("") - assert result is None - - def test_hash_key_consistent(self): - """Hash function is consistent""" - key = "test-key" - hash1 = _hash_key(key) - hash2 = _hash_key(key) - assert hash1 == hash2 - - def test_hash_key_unique(self): - """Different keys produce different hashes""" - hash1 = _hash_key("key1") - hash2 = _hash_key("key2") - assert hash1 != hash2 - - -# ============================================================================= -# HEALTH ENDPOINT TESTS -# ============================================================================= - - -class TestHealthEndpoint: - """Tests for health check endpoint""" - - def test_health_endpoint(self, client): - """Health endpoint returns 200""" - response = client.get("/health") - assert response.status_code == 200 - - def test_health_response_structure(self, client): - """Health response has correct structure""" - response = client.get("/health") - data = response.json() - - assert "status" in data - assert "version" in data - assert "uptime_seconds" in data - assert "components" in data - - def test_health_version(self, client): - """Health returns correct version""" - response = client.get("/health") - data = response.json() - assert data["version"] == API_VERSION - - def test_root_endpoint(self, client): - """Root endpoint returns API info""" - response = client.get("/") - assert response.status_code == 200 - data = response.json() - assert "name" in data - assert "version" in data - - -# ============================================================================= -# QUERY ENDPOINT TESTS -# ============================================================================= - - -class TestQueryEndpoint: - """Tests for medical query endpoint""" - - def test_query_requires_auth(self, client): - """Query endpoint requires authentication""" - response = client.post("/api/v1/query", json={"query": "diabetes"}) - assert response.status_code == 401 - - def test_query_with_auth(self, client, auth_headers): - """Query with valid auth returns 200""" - response = client.post( - "/api/v1/query", json={"query": "diabetes tipo 2"}, headers=auth_headers - ) - assert response.status_code == 200 - - def test_query_response_structure(self, client, auth_headers): - """Query response has correct structure""" - response = client.post( - "/api/v1/query", - json={"query": "hipertensión arterial"}, - headers=auth_headers, - ) - data = response.json() - - assert "status" in data - assert "query" in data - assert "response" in data - assert "language" in data - assert "processing_time_ms" in data - assert "disclaimer" in data - - def test_query_language_spanish(self, client, auth_headers): - """Query returns Spanish response""" - response = client.post( - "/api/v1/query", - json={"query": "diabetes", "language": "es"}, - headers=auth_headers, - ) - data = response.json() - assert data["language"] == "es" - - def test_query_language_english(self, client, auth_headers): - """Query returns English response""" - response = client.post( - "/api/v1/query", - json={"query": "diabetes", "language": "en"}, - headers=auth_headers, - ) - data = response.json() - assert data["language"] == "en" - - def test_query_emergency_detection(self, client, auth_headers): - """Query detects emergency keywords""" - response = client.post( - "/api/v1/query", - json={"query": "dolor en el pecho e infarto"}, - headers=auth_headers, - ) - data = response.json() - # May or may not be emergency depending on detection - assert "is_emergency" in data - - def test_query_validation_short(self, client, auth_headers): - """Query validation rejects short queries""" - response = client.post( - "/api/v1/query", - json={"query": "ab"}, # Too short - headers=auth_headers, - ) - assert response.status_code == 422 - - def test_query_with_sources(self, client, auth_headers): - """Query includes sources when requested""" - response = client.post( - "/api/v1/query", - json={"query": "metformina", "include_sources": True}, - headers=auth_headers, - ) - data = response.json() - assert "sources" in data - - -# ============================================================================= -# DDX ENDPOINT TESTS -# ============================================================================= - - -class TestDDxEndpoint: - """Tests for differential diagnosis endpoint""" - - def test_ddx_requires_auth(self, client): - """DDx endpoint requires authentication""" - response = client.post("/api/v1/ddx", json={"symptom": "dolor torácico"}) - assert response.status_code == 401 - - def test_ddx_with_auth(self, client, auth_headers): - """DDx with valid auth returns 200""" - response = client.post( - "/api/v1/ddx", json={"symptom": "dolor torácico"}, headers=auth_headers - ) - assert response.status_code == 200 - - def test_ddx_response_structure(self, client, auth_headers): - """DDx response has correct structure""" - response = client.post( - "/api/v1/ddx", json={"symptom": "cefalea"}, headers=auth_headers - ) - data = response.json() - - assert "status" in data - assert "symptom" in data - assert "differentials" in data - assert "total_count" in data - assert "processing_time_ms" in data - assert "disclaimer" in data - - def test_ddx_returns_diagnoses(self, client, auth_headers): - """DDx returns list of diagnoses""" - response = client.post( - "/api/v1/ddx", json={"symptom": "dolor torácico"}, headers=auth_headers - ) - data = response.json() - - # May return differentials if symptom is recognized - assert isinstance(data["differentials"], list) - - def test_ddx_with_red_flags(self, client, auth_headers): - """DDx includes red flags when requested""" - response = client.post( - "/api/v1/ddx", - json={"symptom": "cefalea", "include_red_flags": True}, - headers=auth_headers, - ) - data = response.json() - - # Check structure includes red_flags field - for dx in data.get("differentials", []): - assert "red_flags" in dx - - def test_ddx_symptoms_list(self, client, auth_headers): - """Get available symptoms list""" - response = client.get("/api/v1/ddx/symptoms", headers=auth_headers) - assert response.status_code == 200 - data = response.json() - - assert "symptoms" in data - assert "count" in data - assert isinstance(data["symptoms"], list) - - -# ============================================================================= -# KB SEARCH ENDPOINT TESTS -# ============================================================================= - - -class TestKBSearchEndpoint: - """Tests for knowledge base search endpoint""" - - def test_kb_search_requires_auth(self, client): - """KB search requires authentication""" - response = client.post("/api/v1/kb/search", json={"query": "diabetes"}) - assert response.status_code == 401 - - def test_kb_search_with_auth(self, client, auth_headers): - """KB search with valid auth returns 200""" - response = client.post( - "/api/v1/kb/search", json={"query": "diabetes"}, headers=auth_headers - ) - assert response.status_code == 200 - - def test_kb_search_response_structure(self, client, auth_headers): - """KB search response has correct structure""" - response = client.post( - "/api/v1/kb/search", json={"query": "metformina"}, headers=auth_headers - ) - data = response.json() - - assert "status" in data - assert "query" in data - assert "results" in data - assert "total_count" in data - assert "limit" in data - assert "offset" in data - assert "processing_time_ms" in data - - def test_kb_search_returns_results(self, client, auth_headers): - """KB search returns results for known terms""" - response = client.post( - "/api/v1/kb/search", json={"query": "diabetes"}, headers=auth_headers - ) - data = response.json() - - assert isinstance(data["results"], list) - - def test_kb_search_pagination(self, client, auth_headers): - """KB search respects pagination""" - response = client.post( - "/api/v1/kb/search", - json={"query": "cardio", "limit": 5, "offset": 0}, - headers=auth_headers, - ) - data = response.json() - - assert data["limit"] == 5 - assert data["offset"] == 0 - - def test_kb_search_category_filter(self, client, auth_headers): - """KB search filters by category""" - response = client.post( - "/api/v1/kb/search", - json={"query": "diabetes", "category": "conditions"}, - headers=auth_headers, - ) - data = response.json() - - # All results should be conditions - for result in data.get("results", []): - assert result["type"] == "condition" - - def test_kb_condition_by_icd10(self, client, auth_headers): - """Get condition by ICD-10 code""" - response = client.get("/api/v1/kb/conditions/E11", headers=auth_headers) - # May return 200 or 404 depending on KB content - assert response.status_code in [200, 404] - - def test_kb_condition_not_found(self, client, auth_headers): - """Get non-existent condition returns 404""" - response = client.get("/api/v1/kb/conditions/XXXXX", headers=auth_headers) - assert response.status_code == 404 - - -# ============================================================================= -# STATS ENDPOINT TESTS -# ============================================================================= - - -class TestStatsEndpoint: - """Tests for statistics endpoint""" - - def test_stats_requires_auth(self, client): - """Stats endpoint requires authentication""" - response = client.get("/api/v1/stats") - assert response.status_code == 401 - - def test_stats_with_auth(self, client, auth_headers): - """Stats with valid auth returns 200""" - response = client.get("/api/v1/stats", headers=auth_headers) - assert response.status_code == 200 - - def test_stats_response_structure(self, client, auth_headers): - """Stats response has correct structure""" - response = client.get("/api/v1/stats", headers=auth_headers) - data = response.json() - - assert "conditions_count" in data - assert "medications_count" in data - assert "symptoms_ddx_count" in data - assert "languages_supported" in data - assert "api_version" in data - - -# ============================================================================= -# SERVICE TESTS -# ============================================================================= - - -class TestServices: - """Tests for API services""" - - def test_query_service_singleton(self): - """Query service is singleton""" - s1 = get_query_service() - s2 = get_query_service() - assert s1 is s2 - - def test_ddx_service_singleton(self): - """DDx service is singleton""" - s1 = get_ddx_service() - s2 = get_ddx_service() - assert s1 is s2 - - def test_kb_service_singleton(self): - """KB service is singleton""" - s1 = get_kb_service() - s2 = get_kb_service() - assert s1 is s2 - - def test_query_service_initialized(self): - """Query service initializes correctly""" - service = get_query_service() - assert hasattr(service, "_initialized") - - def test_ddx_service_initialized(self): - """DDx service initializes correctly""" - service = get_ddx_service() - assert hasattr(service, "_initialized") - - def test_kb_service_initialized(self): - """KB service initializes correctly""" - service = get_kb_service() - assert hasattr(service, "_initialized") - - -# ============================================================================= -# MODEL TESTS -# ============================================================================= - - -class TestModels: - """Tests for Pydantic models""" - - def test_language_enum(self): - """Language enum values""" - assert Language.ES.value == "es" - assert Language.EN.value == "en" - - def test_user_type_enum(self): - """UserType enum values""" - assert UserType.PROFESSIONAL.value == "professional" - assert UserType.EDUCATIONAL.value == "educational" - assert UserType.EMERGENCY.value == "emergency" - - def test_urgency_level_enum(self): - """UrgencyLevel enum values""" - assert UrgencyLevel.EMERGENT.value == "emergent" - assert UrgencyLevel.URGENT.value == "urgent" - - def test_response_status_enum(self): - """ResponseStatus enum values""" - assert ResponseStatus.SUCCESS.value == "success" - assert ResponseStatus.ERROR.value == "error" - - -# ============================================================================= -# ERROR HANDLING TESTS -# ============================================================================= - - -class TestErrorHandling: - """Tests for error handling""" - - def test_invalid_auth_returns_403(self, client, invalid_auth_headers): - """Invalid API key returns 403""" - response = client.post( - "/api/v1/query", json={"query": "test query"}, headers=invalid_auth_headers - ) - assert response.status_code == 403 - - def test_missing_auth_returns_401(self, client): - """Missing API key returns 401""" - response = client.post("/api/v1/query", json={"query": "test query"}) - assert response.status_code == 401 - - def test_invalid_json_returns_422(self, client, auth_headers): - """Invalid JSON body returns 422""" - response = client.post( - "/api/v1/query", - content="not valid json", - headers={**auth_headers, "Content-Type": "application/json"}, - ) - assert response.status_code == 422 - - def test_missing_required_field_returns_422(self, client, auth_headers): - """Missing required field returns 422""" - response = client.post( - "/api/v1/query", - json={}, # Missing 'query' field - headers=auth_headers, - ) - assert response.status_code == 422 From 46037d94588da7e11f11985f7eb2a50c34389f18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Romero=20=20=20=20=20-=F0=9D=94=87=F0=9D=94=A2?= =?UTF-8?q?=F0=9D=94=A2=F0=9D=94=AD=E2=84=9C=F0=9D=94=9E=F0=9D=94=B1?= Date: Thu, 26 Feb 2026 15:28:25 -0300 Subject: [PATCH 2/4] fix: remove V1 test_i18n.py (i18n module does not exist) No i18n module exists in V2. Issue #4 will create the multi-language module with proper tests. --- tests/test_i18n.py | 234 --------------------------------------------- 1 file changed, 234 deletions(-) delete mode 100644 tests/test_i18n.py diff --git a/tests/test_i18n.py b/tests/test_i18n.py deleted file mode 100644 index 2c099b7..0000000 --- a/tests/test_i18n.py +++ /dev/null @@ -1,234 +0,0 @@ -""" -Tests para el módulo i18n de MedeX -================================== -Verifica traducciones, cambio de idioma y funciones helper. -""" - -import pytest -from i18n import ( - TRANSLATIONS, - Language, - Translator, - get_language, - get_translator, - set_language, - t, -) - - -class TestTranslator: - """Tests para la clase Translator""" - - def test_translator_initialization(self): - """Verificar inicialización con idioma por defecto""" - translator = Translator() - assert translator.language == "es" - - def test_translator_with_custom_language(self): - """Verificar inicialización con idioma personalizado""" - translator = Translator(language="en") - assert translator.language == "en" - - def test_translator_call_spanish(self): - """Verificar traducción en español""" - translator = Translator(language="es") - result = translator("app_title") - assert result == "MedeX - Sistema de IA Médica" - - def test_translator_call_english(self): - """Verificar traducción en inglés""" - translator = Translator(language="en") - result = translator("app_title") - assert result == "MedeX - Medical AI System" - - def test_translator_missing_key(self): - """Verificar comportamiento con clave inexistente""" - translator = Translator() - result = translator("nonexistent_key_12345") - assert result == "[nonexistent_key_12345]" - - def test_set_language(self): - """Verificar cambio de idioma""" - translator = Translator(language="es") - assert translator.get_language() == "es" - - translator.set_language("en") - assert translator.get_language() == "en" - - def test_set_invalid_language(self): - """Verificar que idioma inválido no cambia el estado""" - translator = Translator(language="es") - translator.set_language("fr") # francés no soportado - assert translator.get_language() == "es" # debe mantener español - - def test_get_available_languages(self): - """Verificar idiomas disponibles""" - translator = Translator() - langs = translator.get_available_languages() - - assert "es" in langs - assert "en" in langs - assert langs["es"] == "Español" - assert langs["en"] == "English" - - -class TestGlobalFunctions: - """Tests para funciones globales del módulo""" - - def test_get_translator_singleton(self): - """Verificar que get_translator retorna singleton""" - t1 = get_translator() - t2 = get_translator() - assert t1 is t2 - - def test_t_shortcut_spanish(self): - """Verificar función t() en español""" - set_language("es") - result = t("knowledge_base") - assert result == "Base de Conocimiento" - - def test_t_shortcut_english(self): - """Verificar función t() en inglés""" - set_language("en") - result = t("knowledge_base") - assert result == "Knowledge Base" - - def test_set_and_get_language(self): - """Verificar set_language y get_language""" - set_language("es") - assert get_language() == "es" - - set_language("en") - assert get_language() == "en" - - -class TestTranslationKeys: - """Tests para verificar que todas las claves tienen traducciones""" - - def test_all_keys_have_spanish(self): - """Verificar que todas las claves tienen traducción española""" - for key, translations in TRANSLATIONS.items(): - assert "es" in translations, f"Missing Spanish translation for: {key}" - assert translations["es"], f"Empty Spanish translation for: {key}" - - def test_all_keys_have_english(self): - """Verificar que todas las claves tienen traducción inglesa""" - for key, translations in TRANSLATIONS.items(): - assert "en" in translations, f"Missing English translation for: {key}" - assert translations["en"], f"Empty English translation for: {key}" - - def test_critical_keys_exist(self): - """Verificar que claves críticas existen""" - critical_keys = [ - "app_title", - "app_subtitle", - "knowledge_base", - "emergency_detected", - "emergency_protocol", - "disclaimer_educational", - "disclaimer_emergency", - "conditions", - "medications", - "search_kb", - "user_professional", - "user_educational", - "differential_diagnosis", - "clear_history", - ] - - for key in critical_keys: - assert key in TRANSLATIONS, f"Critical key missing: {key}" - - -class TestUITranslations: - """Tests para traducciones específicas de la UI""" - - def test_emergency_translations(self): - """Verificar traducciones de emergencia""" - set_language("es") - assert "EMERGENCIA" in t("emergency_detected") - - set_language("en") - assert "EMERGENCY" in t("emergency_detected") - - def test_user_type_translations(self): - """Verificar traducciones de tipos de usuario""" - set_language("es") - assert "Profesional" in t("user_professional") - assert "Educativo" in t("user_educational") - - set_language("en") - assert "Professional" in t("user_professional") - assert "Educational" in t("user_educational") - - def test_medication_field_translations(self): - """Verificar traducciones de campos de medicamentos""" - med_keys = [ - "mechanism", - "indications", - "contraindications", - "adverse_effects", - "interactions", - "dosing", - "monitoring", - ] - - for key in med_keys: - set_language("es") - es_val = t(key) - assert es_val != f"[{key}]", f"Missing Spanish for {key}" - - set_language("en") - en_val = t(key) - assert en_val != f"[{key}]", f"Missing English for {key}" - - -class TestLanguageEnum: - """Tests para el enum Language""" - - def test_language_values(self): - """Verificar valores del enum""" - assert Language.ES.value == "es" - assert Language.EN.value == "en" - - def test_language_members(self): - """Verificar miembros del enum""" - members = list(Language) - assert len(members) == 2 - assert Language.ES in members - assert Language.EN in members - - -class TestTranslationConsistency: - """Tests para consistencia de traducciones""" - - def test_translations_not_identical(self): - """Verificar que traducciones ES/EN son diferentes para claves principales""" - different_expected = [ - "app_title", - "app_subtitle", - "knowledge_base", - "conditions", - "medications", - "emergency_detected", - ] - - for key in different_expected: - es = TRANSLATIONS[key]["es"] - en = TRANSLATIONS[key]["en"] - assert es != en, f"ES and EN should differ for: {key}" - - def test_translation_length_reasonable(self): - """Verificar que traducciones no están vacías o excesivamente largas""" - for key, translations in TRANSLATIONS.items(): - for lang, text in translations.items(): - assert len(text) > 0, f"Empty translation: {key}/{lang}" - assert len(text) < 2000, f"Excessively long translation: {key}/{lang}" - - -# Cleanup después de tests -@pytest.fixture(autouse=True) -def reset_language(): - """Resetear idioma a español después de cada test""" - yield - set_language("es") From ff6b28b56fd50e5824df8a4bb0b9ebc8aa772063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Romero=20=20=20=20=20-=F0=9D=94=87=F0=9D=94=A2?= =?UTF-8?q?=F0=9D=94=A2=F0=9D=94=AD=E2=84=9C=F0=9D=94=9E=F0=9D=94=B1?= Date: Thu, 26 Feb 2026 15:28:26 -0300 Subject: [PATCH 3/4] ci: promote test_medex_logger to required, remove legacy job - Added test_medex_logger.py to required test matrix (39/39 pass) - Removed Legacy Tests job (no legacy test files remain) - Cleaned up extended test ignore list --- .github/workflows/ci.yml | 62 ++++++++-------------------------------- 1 file changed, 12 insertions(+), 50 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index af1cefc..50baae2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,6 +91,7 @@ jobs: tests/test_api_v2.py \ tests/test_detection.py \ tests/test_differential_diagnosis.py \ + tests/test_medex_logger.py \ -v --tb=short \ --continue-on-collection-errors env: @@ -152,14 +153,14 @@ jobs: run: docker inspect medx:test > /dev/null 2>&1 # ========================================================================= - # INFORMATIONAL: Extended V2 tests — not required, tracked in Issue #2 + # INFORMATIONAL: Extended V2 tests — not blocking # These tests have structural failures due to API/model constructor # changes during V2 development. Tests reference renamed methods or - # changed dataclass fields. Plan: fix in milestone v0.1.1. + # changed dataclass fields. Plan: fix progressively in v0.1.1. # - # Coverage: test_agent, test_integration_v2, test_llm, test_medical, - # test_observability, test_rag, test_security, test_tools, - # test_memory + # Coverage: test_agent, test_engine, test_integration_v2, test_llm, + # test_medical, test_memory, test_observability, test_rag, + # test_security, test_tools # ========================================================================= test-extended: name: Extended Tests (informational) @@ -189,59 +190,20 @@ jobs: - name: Run extended tests (known structural failures) continue-on-error: true run: | - echo "::notice::Extended V2 tests — informational only (Issue #2)" - echo "::notice::These tests have structural failures from API changes during V2 development" + echo "::notice::Extended V2 tests — informational only" pytest tests/ -v --tb=short \ --ignore=tests/e2e/ \ --ignore=tests/test_infrastructure.py \ - --ignore=tests/test_api.py \ - --ignore=tests/test_i18n.py \ - --ignore=tests/test_medex_logger.py \ --ignore=tests/test_api_v2.py \ --ignore=tests/test_detection.py \ --ignore=tests/test_differential_diagnosis.py \ + --ignore=tests/test_medex_logger.py \ --continue-on-collection-errors 2>&1 | tail -50 || true env: MEDEX_ENV: test PYTHONDONTWRITEBYTECODE: "1" - # ========================================================================= - # INFORMATIONAL: Legacy V1 tests — not required, tracked in Issue #2 - # These tests use V1-style imports (api.main, i18n, medex_logger) - # that reference modules not packaged in the V2 architecture. - # Plan: fix imports → move to required (see milestone v0.1.1) - # ========================================================================= - test-legacy: - name: Legacy Tests (informational) - runs-on: ubuntu-latest - continue-on-error: true - - steps: - - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.12" - cache: "pip" - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install fastapi uvicorn pydantic pydantic-settings python-dotenv - pip install aiohttp httpx requests websockets anyio markdown - pip install sqlalchemy alembic asyncpg psycopg2-binary redis qdrant-client - pip install scikit-learn numpy scipy pandas Pillow - pip install huggingface-hub openai sentence-transformers - pip install pytest pytest-asyncio pytest-cov pytest-mock - pip install -e . --no-deps - - - name: Run legacy tests (expected failures) - continue-on-error: true - run: | - echo "::notice::Legacy V1 tests — informational only (Issue #2)" - pytest tests/test_api.py tests/test_i18n.py tests/test_medex_logger.py \ - -v --tb=short --continue-on-collection-errors 2>&1 | tail -30 || true - env: - MEDEX_ENV: test - PYTHONDONTWRITEBYTECODE: "1" + # Legacy V1 test job removed: Issue #2 resolved. + # - test_api.py deleted (V1 api/ module removed; test_api_v2.py covers V2 API) + # - test_i18n.py deleted (no i18n module exists; Issue #4 will build it) + # - test_medex_logger.py promoted to required tests (39/39 pass) From 6a7dc315886dfdb8febb0989e5c1fc4695f1cf5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20Romero=20=20=20=20=20-=F0=9D=94=87=F0=9D=94=A2?= =?UTF-8?q?=F0=9D=94=A2=F0=9D=94=AD=E2=84=9C=F0=9D=94=9E=F0=9D=94=B1?= Date: Thu, 26 Feb 2026 15:29:13 -0300 Subject: [PATCH 4/4] ci: promote test_medex_logger to required, remove legacy job - Added test_medex_logger.py to required test matrix (39/39 pass) - Removed Legacy Tests job (no legacy test files remain) - Cleaned up extended test ignore list