conftest.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. """
  2. Global pytest configuration and fixtures for RAG System tests.
  3. This module provides shared test fixtures and configuration that are available
  4. to all test modules across the test suite.
  5. """
  6. import asyncio
  7. import pytest
  8. from typing import AsyncGenerator, Generator
  9. from pathlib import Path
  10. # ============================================================================
  11. # Event Loop Configuration
  12. # ============================================================================
  13. @pytest.fixture(scope="session")
  14. def event_loop() -> Generator[asyncio.AbstractEventLoop, None, None]:
  15. """
  16. Create an event loop for the entire test session.
  17. This fixture ensures that async tests have access to a properly configured
  18. event loop. The loop is created once per test session and cleaned up after
  19. all tests complete.
  20. Yields:
  21. asyncio.AbstractEventLoop: The event loop for async tests
  22. """
  23. loop = asyncio.get_event_loop_policy().new_event_loop()
  24. yield loop
  25. loop.close()
  26. # ============================================================================
  27. # Singleton Reset
  28. # ============================================================================
  29. @pytest.fixture(autouse=True)
  30. def reset_singletons() -> Generator[None, None, None]:
  31. """
  32. Reset singleton instances between tests.
  33. This fixture automatically runs before each test to ensure that singleton
  34. instances (like configuration objects) are reset, preventing test pollution.
  35. Yields:
  36. None
  37. """
  38. yield
  39. # Clear any cached configuration instances
  40. from functools import lru_cache
  41. # Note: Specific singleton reset logic will be added as needed
  42. # For example: get_settings.cache_clear() when settings are implemented
  43. # ============================================================================
  44. # Test Data Paths
  45. # ============================================================================
  46. @pytest.fixture(scope="session")
  47. def test_data_dir() -> Path:
  48. """
  49. Get the path to the test data directory.
  50. Returns:
  51. Path: Path to tests/fixtures directory
  52. """
  53. return Path(__file__).parent / "fixtures"
  54. @pytest.fixture(scope="session")
  55. def sample_documents_dir(test_data_dir: Path) -> Path:
  56. """
  57. Get the path to sample documents for testing.
  58. Args:
  59. test_data_dir: Path to test data directory
  60. Returns:
  61. Path: Path to sample documents directory
  62. """
  63. return test_data_dir / "documents"
  64. # ============================================================================
  65. # Mock Configuration
  66. # ============================================================================
  67. @pytest.fixture
  68. def mock_settings() -> dict:
  69. """
  70. Provide mock settings for testing.
  71. Returns:
  72. dict: Mock configuration settings
  73. """
  74. return {
  75. "app_name": "RAG System Test",
  76. "debug": True,
  77. "vector_db_type": "infinity",
  78. "database": {
  79. "host": "localhost",
  80. "port": 5432,
  81. "database": "test_rag_system",
  82. "username": "test_user",
  83. "password": "test_password",
  84. },
  85. "infinity": {
  86. "host": "localhost",
  87. "port": 23817,
  88. },
  89. "elasticsearch": {
  90. "host": "localhost",
  91. "port": 9200,
  92. },
  93. }
  94. # ============================================================================
  95. # Test Database Fixtures
  96. # ============================================================================
  97. @pytest.fixture
  98. async def test_db_session() -> AsyncGenerator:
  99. """
  100. Provide a test database session.
  101. This fixture will be implemented when the database infrastructure is ready.
  102. It should provide an isolated database session for each test.
  103. Yields:
  104. Database session for testing
  105. """
  106. # TODO: Implement when database infrastructure is ready
  107. # Example:
  108. # async with get_test_session_factory()() as session:
  109. # yield session
  110. # await session.rollback()
  111. yield None
  112. # ============================================================================
  113. # Mock External Services
  114. # ============================================================================
  115. @pytest.fixture
  116. def mock_vector_db():
  117. """
  118. Provide a mock vector database for testing.
  119. This fixture will be implemented when vector database infrastructure is ready.
  120. Returns:
  121. Mock vector database instance
  122. """
  123. # TODO: Implement when vector database infrastructure is ready
  124. return None
  125. @pytest.fixture
  126. def mock_embedding_service():
  127. """
  128. Provide a mock embedding service for testing.
  129. This fixture generates fake embeddings for testing purposes.
  130. Returns:
  131. Mock embedding service instance
  132. """
  133. # TODO: Implement when embedding service is ready
  134. return None
  135. # ============================================================================
  136. # Test Markers Configuration
  137. # ============================================================================
  138. def pytest_configure(config):
  139. """
  140. Configure custom pytest markers.
  141. Args:
  142. config: pytest configuration object
  143. """
  144. config.addinivalue_line(
  145. "markers", "unit: Unit tests that test individual components in isolation"
  146. )
  147. config.addinivalue_line(
  148. "markers", "integration: Integration tests that test component interactions"
  149. )
  150. config.addinivalue_line(
  151. "markers", "e2e: End-to-end tests that test complete user workflows"
  152. )
  153. config.addinivalue_line(
  154. "markers", "slow: Tests that take a long time to run (> 1 second)"
  155. )
  156. config.addinivalue_line(
  157. "markers", "requires_db: Tests that require a database connection"
  158. )
  159. config.addinivalue_line(
  160. "markers", "requires_vector_db: Tests that require a vector database connection"
  161. )
  162. config.addinivalue_line(
  163. "markers", "requires_external_service: Tests that require external services"
  164. )
  165. config.addinivalue_line(
  166. "markers", "property: Property-based tests using Hypothesis"
  167. )
  168. config.addinivalue_line(
  169. "markers", "asyncio: Async tests using pytest-asyncio"
  170. )
  171. # ============================================================================
  172. # Test Collection Configuration
  173. # ============================================================================
  174. def pytest_collection_modifyitems(config, items):
  175. """
  176. Modify test collection to add markers based on test location.
  177. Args:
  178. config: pytest configuration object
  179. items: List of collected test items
  180. """
  181. for item in items:
  182. # Add markers based on test file location
  183. if "unit" in str(item.fspath):
  184. item.add_marker(pytest.mark.unit)
  185. elif "integration" in str(item.fspath):
  186. item.add_marker(pytest.mark.integration)
  187. elif "e2e" in str(item.fspath):
  188. item.add_marker(pytest.mark.e2e)