Spaces:
Sleeping
Sleeping
Seth McKnight
Implement App Factory pattern with lazy loading and improve test isolation (#62)
2eb9a5f
| import os | |
| import sys | |
| # Ensure project root and src are on sys.path for tests | |
| PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) | |
| SRC_PATH = os.path.join(PROJECT_ROOT, "src") | |
| if PROJECT_ROOT not in sys.path: | |
| sys.path.insert(0, PROJECT_ROOT) | |
| if SRC_PATH not in sys.path: | |
| sys.path.insert(0, SRC_PATH) | |
| # Set environment variables to disable ChromaDB telemetry | |
| os.environ["ANONYMIZED_TELEMETRY"] = "False" | |
| os.environ["CHROMA_TELEMETRY"] = "False" | |
| from unittest.mock import MagicMock, patch # noqa: E402 | |
| import pytest # noqa: E402 | |
| from app import app as flask_app # noqa: E402 | |
| def disable_chromadb_telemetry(): | |
| """Disable ChromaDB telemetry to avoid errors in tests""" | |
| patches = [] | |
| try: | |
| # Patch multiple telemetry-related functions | |
| patches.extend( | |
| [ | |
| patch("chromadb.telemetry.product.posthog.capture", return_value=None), | |
| patch( | |
| "chromadb.telemetry.product.posthog.Posthog.capture", | |
| return_value=None, | |
| ), | |
| patch( | |
| "chromadb.telemetry.product.posthog.Posthog", | |
| return_value=MagicMock(), | |
| ), | |
| patch("chromadb.configure", return_value=None), | |
| ] | |
| ) | |
| for p in patches: | |
| p.start() | |
| yield | |
| except (ImportError, AttributeError): | |
| # If modules don't exist, continue without patching | |
| yield | |
| finally: | |
| for p in patches: | |
| try: | |
| p.stop() | |
| except Exception: | |
| pass | |
| def app(): | |
| """Flask application fixture.""" | |
| # Clear any cached services before each test to prevent state contamination | |
| flask_app.config["RAG_PIPELINE"] = None | |
| flask_app.config["INGESTION_PIPELINE"] = None | |
| flask_app.config["SEARCH_SERVICE"] = None | |
| # Also clear any module-level caches that might exist | |
| import sys | |
| modules_to_clear = [ | |
| "src.rag.rag_pipeline", | |
| "src.llm.llm_service", | |
| "src.search.search_service", | |
| "src.embedding.embedding_service", | |
| "src.vector_store.vector_db", | |
| ] | |
| for module_name in modules_to_clear: | |
| if module_name in sys.modules: | |
| # Clear any cached instances on the module | |
| module = sys.modules[module_name] | |
| for attr_name in dir(module): | |
| attr = getattr(module, attr_name) | |
| if hasattr(attr, "__dict__") and not attr_name.startswith("_"): | |
| # Clear instance dictionaries that might contain cached data | |
| if hasattr(attr, "_instances"): | |
| attr._instances = {} | |
| yield flask_app | |
| def client(app): | |
| """Flask test client fixture.""" | |
| return app.test_client() | |
| def reset_mock_state(): | |
| """Fixture to reset any global mock state between tests.""" | |
| yield | |
| # Clean up any lingering mock state after each test | |
| import unittest.mock | |
| # Clear any patches that might have been left hanging | |
| unittest.mock.patch.stopall() | |