Files
portfolio-hub/tests/test_users.py
T
2026-04-03 12:23:44 +00:00

132 lines
4.9 KiB
Python

from __future__ import annotations
from datetime import datetime, timezone
from fastapi.testclient import TestClient
from app.domain.models import User
from app.main import app
from app.services.user_service import UserService, get_user_service
class FakeUserRepo:
def __init__(self) -> None:
self.users: dict[str, User] = {}
self.next_id = 1
def get_user(self, user_id: str) -> User:
user = self.users.get(user_id)
if user is None:
raise ValueError("사용자를 찾을 수 없습니다")
return user
def list_users(self) -> list[User]:
return sorted(self.users.values(), key=lambda user: user.username)
def create_user(self, username: str, *, email: str | None = None) -> User:
if any(user.username == username for user in self.users.values()):
raise ValueError(f"이미 존재하는 username입니다: {username}")
if email is not None and any(user.email == email for user in self.users.values()):
raise ValueError(f"이미 존재하는 email입니다: {email}")
now = datetime.now(timezone.utc)
user = User(
id=f"user-{self.next_id}",
username=username,
email=email,
created_at=now,
updated_at=now,
)
self.next_id += 1
self.users[user.id] = user
return user
def update_user(self, user_id: str, *, username: str | None = None, email: str | None = None) -> User:
user = self.get_user(user_id)
if username is not None and any(item.id != user_id and item.username == username for item in self.users.values()):
raise ValueError(f"이미 존재하는 username입니다: {username}")
if email is not None and any(item.id != user_id and item.email == email for item in self.users.values()):
raise ValueError(f"이미 존재하는 email입니다: {email}")
if username is not None:
user.username = username
if email is not None:
user.email = email
user.updated_at = datetime.now(timezone.utc)
return user
def delete_user(self, user_id: str) -> None:
if user_id not in self.users:
raise ValueError("사용자를 찾을 수 없습니다")
del self.users[user_id]
def _client_with_repo(monkeypatch, repo: FakeUserRepo) -> TestClient:
monkeypatch.setenv("PORTFOLIOHUB_DB_ENABLED", "false")
monkeypatch.setenv("PORTFOLIOHUB_ADMIN_TOKENS", "admin-token")
monkeypatch.setenv("PORTFOLIOHUB_READ_TOKENS", "read-token")
from app.core.config import get_settings
get_settings.cache_clear()
app.dependency_overrides.clear()
app.dependency_overrides[get_user_service] = lambda: UserService(repo)
return TestClient(app)
def test_list_users_requires_admin(monkeypatch) -> None:
client = _client_with_repo(monkeypatch, FakeUserRepo())
response = client.get("/users", headers={"Authorization": "Bearer read-token"})
app.dependency_overrides.clear()
assert response.status_code == 403
assert response.json()["detail"] == "Insufficient permission"
def test_list_users_returns_payload(monkeypatch) -> None:
repo = FakeUserRepo()
repo.create_user("alice", email="alice@example.com")
client = _client_with_repo(monkeypatch, repo)
response = client.get("/users", headers={"Authorization": "Bearer admin-token"})
app.dependency_overrides.clear()
assert response.status_code == 200
payload = response.json()
assert len(payload) == 1
assert payload[0]["username"] == "alice"
def test_create_user_rejects_duplicate_username(monkeypatch) -> None:
repo = FakeUserRepo()
repo.create_user("alice")
client = _client_with_repo(monkeypatch, repo)
response = client.post(
"/users",
headers={"Authorization": "Bearer admin-token"},
json={"username": "alice", "email": "alice2@example.com"},
)
app.dependency_overrides.clear()
assert response.status_code == 409
assert "이미 존재하는 username입니다" in response.json()["detail"]
def test_get_update_and_delete_user_flow(monkeypatch) -> None:
repo = FakeUserRepo()
user = repo.create_user("alice", email="alice@example.com")
client = _client_with_repo(monkeypatch, repo)
get_response = client.get(f"/users/{user.id}", headers={"Authorization": "Bearer admin-token"})
update_response = client.patch(
f"/users/{user.id}",
headers={"Authorization": "Bearer admin-token"},
json={"username": "alice-updated"},
)
delete_response = client.delete(f"/users/{user.id}", headers={"Authorization": "Bearer admin-token"})
app.dependency_overrides.clear()
assert get_response.status_code == 200
assert get_response.json()["username"] == "alice"
assert update_response.status_code == 200
assert update_response.json()["username"] == "alice-updated"
assert delete_response.status_code == 204