291 lines
11 KiB
Python
291 lines
11 KiB
Python
# tests/persistence/test_sqlite_user.py
|
|
|
|
from datetime import datetime
|
|
|
|
import pytest
|
|
|
|
from myauth.exceptions import UserAlreadyExistsError, UserNotFoundError
|
|
from myauth.models.user import UserCreate, UserUpdate
|
|
from myauth.persistence.sqlite import SQLiteUserRepository
|
|
|
|
|
|
def test_i_can_create_and_retrieve_user_by_email(user_repository: SQLiteUserRepository,
|
|
test_user_data_create: UserCreate,
|
|
test_user_hashed_password: str):
|
|
"""Verifies user creation and successful retrieval by email."""
|
|
|
|
# 1. Create User
|
|
created_user = user_repository.create_user(
|
|
user_data=test_user_data_create,
|
|
hashed_password=test_user_hashed_password
|
|
)
|
|
|
|
# Assertions on creation
|
|
assert created_user is not None
|
|
assert created_user.email == test_user_data_create.email
|
|
assert created_user.hashed_password == test_user_hashed_password
|
|
assert created_user.is_active is True
|
|
assert created_user.is_verified is False
|
|
assert created_user.id is not None
|
|
assert isinstance(created_user.created_at, datetime)
|
|
|
|
# 2. Retrieve User
|
|
retrieved_user = user_repository.get_user_by_email(test_user_data_create.email)
|
|
|
|
# Assertions on retrieval
|
|
assert retrieved_user is not None
|
|
assert retrieved_user.id == created_user.id
|
|
assert retrieved_user.username == "TestUser"
|
|
|
|
|
|
def test_i_can_retrieve_user_by_id(user_repository: SQLiteUserRepository,
|
|
test_user_data_create: UserCreate,
|
|
test_user_hashed_password: str):
|
|
"""Verifies user retrieval by unique ID."""
|
|
created_user = user_repository.create_user(test_user_data_create, test_user_hashed_password)
|
|
|
|
retrieved_user = user_repository.get_user_by_id(created_user.id)
|
|
|
|
assert retrieved_user is not None
|
|
assert retrieved_user.email == created_user.email
|
|
|
|
|
|
def test_i_cannot_create_user_if_email_exists(user_repository: SQLiteUserRepository,
|
|
test_user_data_create: UserCreate,
|
|
test_user_hashed_password: str):
|
|
"""Ensures that creating a user with an existing email raises UserAlreadyExistsError."""
|
|
# First creation should succeed
|
|
user_repository.create_user(test_user_data_create, test_user_hashed_password)
|
|
|
|
# Second creation with same email should fail
|
|
with pytest.raises(UserAlreadyExistsError):
|
|
user_repository.create_user(test_user_data_create, test_user_hashed_password)
|
|
|
|
|
|
def test_i_can_check_if_email_exists(user_repository: SQLiteUserRepository,
|
|
test_user_data_create: UserCreate,
|
|
test_user_hashed_password: str):
|
|
"""Verifies the email_exists method returns correct boolean results."""
|
|
email = test_user_data_create.email
|
|
non_existent_email = "non.existent@example.com"
|
|
|
|
# 1. Check before creation (Should be False)
|
|
assert user_repository.email_exists(email) is False
|
|
|
|
user_repository.create_user(test_user_data_create, test_user_hashed_password)
|
|
|
|
# 2. Check after creation (Should be True)
|
|
assert user_repository.email_exists(email) is True
|
|
|
|
# 3. Check for another non-existent email
|
|
assert user_repository.email_exists(non_existent_email) is False
|
|
|
|
|
|
def test_i_can_update_username_and_roles(user_repository: SQLiteUserRepository,
|
|
test_user_data_create: UserCreate,
|
|
test_user_hashed_password: str):
|
|
"""Tests partial update of user fields (username and roles)."""
|
|
|
|
created_user = user_repository.create_user(test_user_data_create, test_user_hashed_password)
|
|
|
|
updates = UserUpdate(username="NewUsername", roles=["admin", "staff"])
|
|
|
|
updated_user = user_repository.update_user(created_user.id, updates)
|
|
|
|
assert updated_user.username == "NewUsername"
|
|
assert updated_user.roles == ["admin", "staff"]
|
|
# Check that unrelated fields remain the same
|
|
assert updated_user.email == created_user.email
|
|
# Check that update timestamp changed
|
|
assert updated_user.updated_at > created_user.updated_at
|
|
assert updated_user.is_verified == created_user.is_verified
|
|
|
|
|
|
def test_i_can_update_is_active_status(user_repository: SQLiteUserRepository,
|
|
test_user_data_create: UserCreate,
|
|
test_user_hashed_password: str):
|
|
"""Tests the specific update of the 'is_active' status."""
|
|
|
|
created_user = user_repository.create_user(test_user_data_create, test_user_hashed_password)
|
|
|
|
# Deactivate
|
|
updates_deactivate = UserUpdate(is_active=False)
|
|
deactivated_user = user_repository.update_user(created_user.id, updates_deactivate)
|
|
assert deactivated_user.is_active is False
|
|
|
|
# Reactivate
|
|
updates_activate = UserUpdate(is_active=True)
|
|
reactivated_user = user_repository.update_user(created_user.id, updates_activate)
|
|
assert reactivated_user.is_active is True
|
|
|
|
|
|
def test_i_cannot_update_non_existent_user(user_repository: SQLiteUserRepository):
|
|
"""Ensures that updating a user with an unknown ID raises UserNotFoundError."""
|
|
non_existent_id = "unknown_id_123"
|
|
updates = UserUpdate(username="Phantom")
|
|
|
|
with pytest.raises(UserNotFoundError):
|
|
user_repository.update_user(non_existent_id, updates)
|
|
|
|
|
|
def test_i_can_delete_user(user_repository: SQLiteUserRepository,
|
|
test_user_data_create: UserCreate,
|
|
test_user_hashed_password: str):
|
|
"""Verifies user deletion and subsequent failure to retrieve."""
|
|
|
|
created_user = user_repository.create_user(test_user_data_create, test_user_hashed_password)
|
|
|
|
# 1. Delete the user
|
|
was_deleted = user_repository.delete_user(created_user.id)
|
|
assert was_deleted is True
|
|
|
|
# 2. Verify deletion by attempting retrieval
|
|
retrieved_user = user_repository.get_user_by_id(created_user.id)
|
|
assert retrieved_user is None
|
|
|
|
# 3. Verify attempting to delete again returns False
|
|
was_deleted_again = user_repository.delete_user(created_user.id)
|
|
assert was_deleted_again is False
|
|
|
|
|
|
def test_i_cannot_retrieve_non_existent_user_by_email(user_repository: SQLiteUserRepository):
|
|
"""Ensures retrieval by email returns None for non-existent email."""
|
|
|
|
retrieved_user = user_repository.get_user_by_email("ghost@example.com")
|
|
assert retrieved_user is None
|
|
|
|
|
|
def test_i_can_list_users_with_pagination(user_repository: SQLiteUserRepository,
|
|
test_user_hashed_password: str):
|
|
"""Verifies that list_users returns paginated results correctly."""
|
|
|
|
# Create multiple users
|
|
for i in range(5):
|
|
user_data = UserCreate(
|
|
email=f"user{i}@example.com",
|
|
username=f"User{i}",
|
|
password="#Password123",
|
|
roles=["user"],
|
|
user_settings={}
|
|
)
|
|
user_repository.create_user(user_data, test_user_hashed_password)
|
|
|
|
# Test: Get first 3 users
|
|
users_page1 = user_repository.list_users(skip=0, limit=3)
|
|
assert len(users_page1) == 3
|
|
|
|
# Test: Get next 2 users
|
|
users_page2 = user_repository.list_users(skip=3, limit=3)
|
|
assert len(users_page2) == 2
|
|
|
|
# Test: Verify no duplicates between pages
|
|
page1_ids = {user.id for user in users_page1}
|
|
page2_ids = {user.id for user in users_page2}
|
|
assert len(page1_ids.intersection(page2_ids)) == 0
|
|
|
|
|
|
def test_i_can_list_users_with_default_pagination(user_repository: SQLiteUserRepository,
|
|
test_user_data_create: UserCreate,
|
|
test_user_hashed_password: str):
|
|
"""Verifies that list_users works with default parameters."""
|
|
|
|
# Create 2 users
|
|
user_repository.create_user(test_user_data_create, test_user_hashed_password)
|
|
|
|
user_data2 = UserCreate(
|
|
email="user2@example.com",
|
|
username="User2",
|
|
password="#Password123",
|
|
roles=["user"],
|
|
user_settings={}
|
|
)
|
|
user_repository.create_user(user_data2, test_user_hashed_password)
|
|
|
|
# Test: Default parameters (skip=0, limit=100)
|
|
users = user_repository.list_users()
|
|
assert len(users) == 2
|
|
assert all(isinstance(user.created_at, datetime) for user in users)
|
|
|
|
|
|
def test_i_get_empty_list_when_no_users_exist(user_repository: SQLiteUserRepository):
|
|
"""Verifies that list_users returns an empty list when no users exist."""
|
|
|
|
users = user_repository.list_users()
|
|
assert users == []
|
|
assert isinstance(users, list)
|
|
|
|
|
|
def test_i_can_skip_beyond_available_users(user_repository: SQLiteUserRepository,
|
|
test_user_data_create: UserCreate,
|
|
test_user_hashed_password: str):
|
|
"""Verifies that skipping beyond available users returns an empty list."""
|
|
|
|
user_repository.create_user(test_user_data_create, test_user_hashed_password)
|
|
|
|
# Skip beyond the only user
|
|
users = user_repository.list_users(skip=10, limit=10)
|
|
assert users == []
|
|
|
|
|
|
def test_i_can_count_users(user_repository: SQLiteUserRepository,
|
|
test_user_hashed_password: str):
|
|
"""Verifies that count_users returns the correct number of users."""
|
|
|
|
# Initial count should be 0
|
|
assert user_repository.count_users() == 0
|
|
|
|
# Create first user
|
|
user_data1 = UserCreate(
|
|
email="user1@example.com",
|
|
username="User1",
|
|
password="#Password123",
|
|
roles=["user"],
|
|
user_settings={}
|
|
)
|
|
user_repository.create_user(user_data1, test_user_hashed_password)
|
|
assert user_repository.count_users() == 1
|
|
|
|
# Create second user
|
|
user_data2 = UserCreate(
|
|
email="user2@example.com",
|
|
username="User2",
|
|
password="#Password123",
|
|
roles=["user"],
|
|
user_settings={}
|
|
)
|
|
user_repository.create_user(user_data2, test_user_hashed_password)
|
|
assert user_repository.count_users() == 2
|
|
|
|
|
|
def test_i_get_zero_count_when_no_users_exist(user_repository: SQLiteUserRepository):
|
|
"""Verifies that count_users returns 0 when the database is empty."""
|
|
|
|
count = user_repository.count_users()
|
|
assert count == 0
|
|
assert isinstance(count, int)
|
|
|
|
|
|
def test_list_users_returns_correct_user_structure(user_repository: SQLiteUserRepository,
|
|
test_user_data_create: UserCreate,
|
|
test_user_hashed_password: str):
|
|
"""Verifies that list_users returns UserInDB objects with all fields."""
|
|
|
|
user_repository.create_user(test_user_data_create, test_user_hashed_password)
|
|
|
|
users = user_repository.list_users()
|
|
|
|
assert len(users) == 1
|
|
user = users[0]
|
|
|
|
# Verify all fields are present and correct type
|
|
assert user.id is not None
|
|
assert user.email == test_user_data_create.email
|
|
assert user.username == test_user_data_create.username
|
|
assert user.hashed_password == test_user_hashed_password
|
|
assert isinstance(user.roles, list)
|
|
assert isinstance(user.user_settings, dict)
|
|
assert isinstance(user.is_verified, bool)
|
|
assert isinstance(user.is_active, bool)
|
|
assert isinstance(user.created_at, datetime)
|
|
assert isinstance(user.updated_at, datetime)
|