Files
PROJECT-CONTORL/backend/tests/conftest.py
beabigegg 1fda7da2c2 feat: implement user authentication module
- Backend (FastAPI):
  - External API authentication (pj-auth-api.vercel.app)
  - JWT token validation with Redis session storage
  - RBAC with department isolation
  - User, Role, Department models with pjctrl_ prefix
  - Alembic migrations with project-specific version table
  - Complete test coverage (13 tests)

- Frontend (React + Vite):
  - AuthContext for state management
  - Login page with error handling
  - Protected route component
  - Dashboard with user info display

- OpenSpec:
  - 7 capability specs defined
  - add-user-auth change archived

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 23:41:37 +08:00

129 lines
3.1 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 setex(self, key, seconds, value):
self.store[key] = value
def delete(self, key):
if key in self.store:
del self.store[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