api/tests/test_user_service.py

193 lines
6.2 KiB
Python

import pytest
from fastapi import HTTPException
from sqlalchemy.orm import Session
from app.models.user import User
from app.models.user_profile import UserProfile
from app.schemas.user import UserCreate, UserUpdate
from app.security import verify_password
from app.services.user_service import (
create_user,
delete_user,
get_user_by_id,
get_user_list,
update_user,
)
class TestGetUserList:
def test_empty(self, db_session: Session):
users = get_user_list(db_session)
assert users == []
def test_with_users(self, db_session: Session):
for i in range(3):
user = User(email=f"test{i}@ex.com", username=f"user{i}", password="x")
db_session.add(user)
db_session.commit()
users = get_user_list(db_session)
assert len(users) == 3
def test_soft_deleted_excluded(self, db_session: Session):
from datetime import datetime
u1 = User(email="active@ex.com", username="active", password="x")
u2 = User(email="deleted@ex.com", username="deleted", password="x", deleted_at=datetime.now())
db_session.add_all([u1, u2])
db_session.commit()
users = get_user_list(db_session)
assert len(users) == 1
assert users[0].email == "active@ex.com"
class TestGetUserById:
def test_found(self, db_session: Session):
user = User(email="find@ex.com", username="find", password="x")
db_session.add(user)
db_session.commit()
result = get_user_by_id(db_session, user.id)
assert result.id == user.id
assert result.email == "find@ex.com"
def test_not_found(self, db_session: Session):
with pytest.raises(HTTPException) as exc:
get_user_by_id(db_session, "nonexistent")
assert exc.value.status_code == 404
def test_soft_deleted(self, db_session: Session):
from datetime import datetime
user = User(email="gone@ex.com", username="gone", password="x", deleted_at=datetime.now())
db_session.add(user)
db_session.commit()
with pytest.raises(HTTPException) as exc:
get_user_by_id(db_session, user.id)
assert exc.value.status_code == 404
class TestCreateUser:
def test_create(self, db_session: Session):
data = UserCreate(
email="new@ex.com",
username="newuser",
password="secret",
full_name="New User",
)
user = create_user(db_session, data)
assert user.email == "new@ex.com"
assert user.username == "newuser"
assert verify_password("secret", user.password)
profile = db_session.query(UserProfile).filter(UserProfile.user_id == user.id).first()
assert profile is not None
assert profile.full_name == "New User"
def test_duplicate_email(self, db_session: Session):
db_session.add(User(email="dup@ex.com", username="first", password="x"))
db_session.commit()
data = UserCreate(
email="dup@ex.com",
username="second",
password="x",
full_name="Dup",
)
with pytest.raises(HTTPException) as exc:
create_user(db_session, data)
assert exc.value.status_code == 409
def test_duplicate_username(self, db_session: Session):
data = UserCreate(
email="a@ex.com",
username="taken",
password="x",
full_name="A",
)
create_user(db_session, data)
dup = UserCreate(
email="b@ex.com",
username="taken",
password="x",
full_name="B",
)
with pytest.raises(HTTPException) as exc:
create_user(db_session, dup)
assert exc.value.status_code == 409
class TestUpdateUser:
def test_update_email(self, db_session: Session):
user = User(email="old@ex.com", username="old", password="x")
db_session.add(user)
db_session.commit()
data = UserUpdate(email="new@ex.com")
updated = update_user(db_session, user.id, data)
assert updated.email == "new@ex.com"
def test_update_profile(self, db_session: Session):
user = User(email="prof@ex.com", username="prof", password="x")
db_session.add(user)
db_session.flush()
profile = UserProfile(user_id=user.id, full_name="Old Name")
db_session.add(profile)
db_session.commit()
data = UserUpdate(full_name="Updated Name")
updated = update_user(db_session, user.id, data)
assert updated.profile.full_name == "Updated Name"
def test_update_password(self, db_session: Session):
user = User(email="pw@ex.com", username="pw", password="x")
db_session.add(user)
db_session.commit()
data = UserUpdate(password="newsecret")
update_user(db_session, user.id, data)
db_session.refresh(user)
assert verify_password("newsecret", user.password)
def test_update_not_found(self, db_session: Session):
data = UserUpdate(email="nope@ex.com")
with pytest.raises(HTTPException) as exc:
update_user(db_session, "nonexistent", data)
assert exc.value.status_code == 404
def test_update_conflict_email(self, db_session: Session):
User(email="existing@ex.com", username="existing", password="x")
user = User(email="me@ex.com", username="me", password="x")
db_session.add_all([User(email="existing@ex.com", username="existing", password="x"), user])
db_session.commit()
data = UserUpdate(email="existing@ex.com")
with pytest.raises(HTTPException) as exc:
update_user(db_session, user.id, data)
assert exc.value.status_code == 409
class TestDeleteUser:
def test_soft_delete(self, db_session: Session):
user = User(email="del@ex.com", username="del", password="x")
db_session.add(user)
db_session.commit()
delete_user(db_session, user.id)
assert user.deleted_at is not None
def test_delete_not_found(self, db_session: Session):
with pytest.raises(HTTPException) as exc:
delete_user(db_session, "nonexistent")
assert exc.value.status_code == 404