# Tests This directory contains the test suite for the capa-de-integracion application. ## Test Dependencies - **pytest** - Test framework - **pytest-asyncio** - Async test support - **pytest-cov** - Coverage reporting - **pytest-env** - Environment variable configuration (cleaner than manual setup) - **pytest-recording** - HTTP recording (configured but not used for gRPC Firestore or Redis) - **fakeredis** - In-memory Redis mock for testing without a container - **inline-snapshot** - Snapshot testing support ## Running Tests ```bash # Run all tests uv run pytest # Run specific test file uv run pytest tests/services/test_firestore_service.py # Run with coverage uv run pytest --cov=capa_de_integracion # Run with verbose output uv run pytest -v ``` ## Redis Service Tests The Redis service tests use **fakeredis**, an in-memory implementation of Redis that doesn't require a running Redis container. **Benefits:** - ✅ No external dependencies - tests run anywhere - ✅ Fast execution - all operations are in-memory - ✅ Automatic cleanup - each test gets a fresh Redis instance - ✅ Full Redis protocol support - tests verify real behavior The `redis_service` and `clean_redis` fixtures automatically use fakeredis, so tests work identically to production code but without needing a container. ## Firestore Service Tests The Firestore service tests require the Firestore emulator to be running. ### Prerequisites 1. **Start the Firestore Emulator**: ```bash gcloud firestore emulators start --host-port=[::1]:8911 ``` Or if using Firebase CLI: ```bash firebase emulators:start --only firestore ``` 2. **Configure Indexes** (optional, for advanced queries): The `firestore.indexes.json` file defines composite indexes needed for some queries. The emulator should automatically apply these when started in the project directory. ### Test Structure - `test_firestore_service.py` - Comprehensive tests for FirestoreService - `TestSessionManagement` - Conversation session CRUD operations - `TestEntryManagement` - Conversation entry operations - `TestNotificationManagement` - Notification operations - `TestEdgeCases` - Edge cases and error handling ### Important Notes #### Why No pytest-recording Cassettes? While pytest-recording is configured in the project, **cassettes are not generated** for Firestore or Redis tests. This is because: - **Firestore uses gRPC protocol**, not HTTP - **Redis uses RESP (Redis Serialization Protocol)**, not HTTP - **pytest-recording/vcrpy only supports HTTP** requests **Solutions:** - **Redis**: Uses **fakeredis** - an in-memory Redis implementation that provides full Redis functionality without requiring a container or cassettes - **Firestore**: Tests run directly against the Firestore emulator, providing: - ✅ Real integration testing with actual Firestore behavior - ✅ No mocking - tests verify actual data operations - ✅ Fast execution (emulator is local) - ❌ Requires emulator to be running If you need offline/recorded Firestore tests, consider: 1. Using the emulator's export/import feature for test data 2. Implementing a mock FirestoreService for unit tests 3. Using snapshot testing with inline-snapshot for assertions ### Composite Index Requirements Some tests require composite indexes (e.g., queries with both `where` and `order_by`): - `test_get_session_by_phone_existing` - Currently **skipped** - Requires index on: `telefono` (ASC) + `lastModified` (DESC) - To enable: Configure index in `firestore.indexes.json` and restart emulator ### Environment Variables Tests automatically configure environment variables via **pytest-env** plugin. Configuration is in `pytest.ini`: ```ini [pytest] env = FIRESTORE_EMULATOR_HOST=[::1]:8911 GCP_PROJECT_ID=test-project GCP_LOCATION=us-central1 GCP_FIRESTORE_DATABASE_ID=(default) RAG_ENDPOINT_URL=http://localhost:8000/rag REDIS_HOST=localhost # Not used - tests use fakeredis REDIS_PORT=6379 # Not used - tests use fakeredis DLP_TEMPLATE_COMPLETE_FLOW=projects/test/dlpJobTriggers/test ``` These are automatically loaded before any test runs, ensuring consistent test environment setup. **Note:** Redis tests use **fakeredis** instead of connecting to the configured REDIS_HOST/REDIS_PORT, so no Redis container is needed. ## Fixtures ### `emulator_settings` Session-scoped fixture providing Settings configured for emulator testing. ### `firestore_service` Function-scoped fixture providing a FirestoreService instance connected to the emulator. Automatically closes the service after each test. ### `clean_firestore` Function-scoped fixture providing a FirestoreService with cleaned collections before and after each test. Use this fixture to ensure test isolation. ## Adding New Tests When adding new Firestore tests: 1. Use `clean_firestore` fixture for test isolation 2. Use the actual model classes (`ConversationSession`, `ConversationEntry`, `Notification`) 3. Use model creation methods (e.g., `ConversationSession.create()`, `Notification.create()`) 4. Assert on actual data structures, not mocked values 5. Consider adding inline-snapshot assertions for complex data validation Example: ```python async def test_new_feature(clean_firestore: FirestoreService) -> None: """Test description.""" # Create test data session = await clean_firestore.create_session( session_id="test-id", user_id="user-123", telefono="+1234567890", ) # Test the feature result = await clean_firestore.some_method(session.session_id) # Assert results assert result is not None assert result.some_field == "expected_value" ```