""" Global test configuration and fixtures for CONTOSO tests. This file provides shared fixtures and configuration for: - Unit tests (with mocked dependencies) - Integration tests (with real database connections) - End-to-end tests (with complete workflow testing) """ import pytest import asyncio import os import tempfile import io from typing import Generator, Dict, Any from fastapi.testclient import TestClient from PIL import Image as PILImage # Import the main app from main import app @pytest.fixture(scope="session") def event_loop(): """Create an event loop for the test session""" loop = asyncio.new_event_loop() yield loop loop.close() @pytest.fixture(scope="session") def test_app(): """Create the FastAPI test application""" return app @pytest.fixture(scope="function") def client(test_app) -> Generator[TestClient, None, None]: """Create a test client for the FastAPI app""" with TestClient(test_app) as test_client: yield test_client @pytest.fixture(scope="function") def sample_image() -> io.BytesIO: """Create a sample image for testing uploads""" img = PILImage.new('RGB', (100, 100), color='red') img_bytes = io.BytesIO() img.save(img_bytes, format='JPEG') img_bytes.seek(0) return img_bytes @pytest.fixture(scope="function") def sample_images() -> Dict[str, io.BytesIO]: """Create multiple sample images for testing""" images = {} colors = ['red', 'green', 'blue', 'yellow'] for i, color in enumerate(colors): img = PILImage.new('RGB', (100, 100), color=color) img_bytes = io.BytesIO() img.save(img_bytes, format='JPEG') img_bytes.seek(0) images[f'{color}_image_{i}.jpg'] = img_bytes return images @pytest.fixture(scope="function") def temp_image_file() -> Generator[str, None, None]: """Create a temporary image file for testing""" img = PILImage.new('RGB', (200, 200), color='blue') with tempfile.NamedTemporaryFile(suffix='.jpg', delete=False) as tmp_file: img.save(tmp_file, format='JPEG') tmp_file_path = tmp_file.name yield tmp_file_path # Cleanup try: os.unlink(tmp_file_path) except OSError: pass @pytest.fixture(scope="function") def test_team_data() -> Dict[str, Any]: """Provide test team data""" return { "name": "Test Team", "description": "A team created for testing purposes" } @pytest.fixture(scope="function") def test_user_data() -> Dict[str, Any]: """Provide test user data""" return { "email": "test@example.com", "name": "Test User", "role": "admin" } @pytest.fixture(scope="function") def test_api_key_data() -> Dict[str, Any]: """Provide test API key data""" return { "name": "Test API Key", "permissions": ["read", "write"] } @pytest.fixture(scope="function") def test_image_data() -> Dict[str, Any]: """Provide test image metadata""" return { "description": "Test image for automated testing", } # Environment-specific fixtures @pytest.fixture(scope="session") def integration_test_enabled() -> bool: """Check if integration tests are enabled""" return bool(os.getenv("FIRESTORE_INTEGRATION_TEST")) @pytest.fixture(scope="session") def e2e_integration_test_enabled() -> bool: """Check if E2E integration tests are enabled""" return bool(os.getenv("E2E_INTEGRATION_TEST")) # Test data cleanup utilities @pytest.fixture(scope="function") def cleanup_tracker(): """Track resources created during tests for cleanup""" resources = { "teams": [], "users": [], "api_keys": [], "images": [] } yield resources # Cleanup logic would go here if needed # For now, we rely on test isolation through mocking # Configuration for different test types def pytest_configure(config): """Configure pytest with custom markers and settings""" config.addinivalue_line( "markers", "unit: mark test as unit test (uses mocks)" ) config.addinivalue_line( "markers", "integration: mark test as integration test (requires real database)" ) config.addinivalue_line( "markers", "e2e: mark test as end-to-end test (complete workflows)" ) config.addinivalue_line( "markers", "slow: mark test as slow running" ) def pytest_collection_modifyitems(config, items): """Modify test collection to add markers based on test location""" for item in items: # Add markers based on test file location if "integration" in str(item.fspath): item.add_marker(pytest.mark.integration) elif "e2e" in str(item.fspath) or item.name.startswith("test_e2e"): item.add_marker(pytest.mark.e2e) else: item.add_marker(pytest.mark.unit) # Skip conditions for different test types def pytest_runtest_setup(item): """Setup conditions for running different types of tests""" # Skip integration tests if not enabled if item.get_closest_marker("integration"): if not os.getenv("FIRESTORE_INTEGRATION_TEST"): pytest.skip("Integration tests disabled. Set FIRESTORE_INTEGRATION_TEST=1 to enable") # Skip E2E integration tests if not enabled if item.get_closest_marker("e2e") and "integration" in item.keywords: if not os.getenv("E2E_INTEGRATION_TEST"): pytest.skip("E2E integration tests disabled. Set E2E_INTEGRATION_TEST=1 to enable")