Files
PROJECT-CONTORL/backend/tests/conftest.py
beabigegg 61fe01cb6b feat: implement workload heatmap module
- Backend (FastAPI):
  - Workload heatmap API with load level calculation
  - User workload detail endpoint with task breakdown
  - Redis caching for workload calculations (1hr TTL)
  - Department isolation and access control
  - WorkloadSnapshot model for historical data
  - Alembic migration for workload_snapshots table

- API Endpoints:
  - GET /api/workload/heatmap - Team workload overview
  - GET /api/workload/user/{id} - User workload detail
  - GET /api/workload/me - Current user workload

- Load Levels:
  - normal: <80%, warning: 80-99%, overloaded: >=100%

- Tests:
  - 26 unit/API tests
  - 15 E2E automated tests
  - 77 total tests passing

- OpenSpec:
  - add-resource-workload change archived
  - resource-management spec updated

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 01:13:21 +08:00

143 lines
3.6 KiB
Python

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