import pytest from fastapi.testclient import TestClient from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from sqlalchemy.pool import StaticPool from app.main import app from app.core.database import Base, get_db from app.core.redis import get_redis from app.models import User, Role, Department # Use in-memory SQLite for testing SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:" engine = create_engine( SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}, poolclass=StaticPool, ) TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) class MockRedis: """Mock Redis client for testing.""" def __init__(self): self.store = {} def get(self, key): return self.store.get(key) def set(self, key, value): self.store[key] = value def setex(self, key, seconds, value): self.store[key] = value def delete(self, key): if key in self.store: del self.store[key] def scan_iter(self, match=None): """Iterate over keys matching a pattern.""" import fnmatch if match is None: yield from self.store.keys() else: pattern = match.replace("*", "**") for key in self.store.keys(): if fnmatch.fnmatch(key, match): yield key @pytest.fixture(scope="function") def db(): """Create a fresh database for each test.""" Base.metadata.create_all(bind=engine) db = TestingSessionLocal() # Create default role admin_role = Role( id="00000000-0000-0000-0000-000000000001", name="super_admin", permissions={"all": True}, is_system_role=True, ) db.add(admin_role) engineer_role = Role( id="00000000-0000-0000-0000-000000000003", name="engineer", permissions={"projects.read": True, "tasks.read": True, "tasks.write": True}, is_system_role=False, ) db.add(engineer_role) # Create system admin user admin_user = User( id="00000000-0000-0000-0000-000000000001", email="ymirliu@panjit.com.tw", name="System Administrator", role_id="00000000-0000-0000-0000-000000000001", is_active=True, is_system_admin=True, ) db.add(admin_user) db.commit() try: yield db finally: db.close() Base.metadata.drop_all(bind=engine) @pytest.fixture(scope="function") def mock_redis(): """Create mock Redis for testing.""" return MockRedis() @pytest.fixture(scope="function") def client(db, mock_redis): """Create test client with overridden dependencies.""" def override_get_db(): try: yield db finally: pass def override_get_redis(): return mock_redis app.dependency_overrides[get_db] = override_get_db app.dependency_overrides[get_redis] = override_get_redis with TestClient(app) as test_client: yield test_client app.dependency_overrides.clear() @pytest.fixture def admin_token(client, mock_redis): """Get an admin token for testing.""" from app.core.security import create_access_token, create_token_payload token_data = create_token_payload( user_id="00000000-0000-0000-0000-000000000001", email="ymirliu@panjit.com.tw", role="super_admin", department_id=None, is_system_admin=True, ) token = create_access_token(token_data) # Store in mock Redis mock_redis.setex("session:00000000-0000-0000-0000-000000000001", 900, token) return token