|
import pytest
|
|
import json
|
|
from retoors.services.user_service import UserService
|
|
import bcrypt
|
|
import datetime
|
|
|
|
@pytest.fixture
|
|
def users_file(tmp_path):
|
|
"""Fixture to create a temporary users.json file for testing."""
|
|
file = tmp_path / "users.json"
|
|
with open(file, "w") as f:
|
|
json.dump([], f) # Start with an empty list of users
|
|
return file
|
|
|
|
@pytest.fixture
|
|
def user_service(users_file):
|
|
"""Fixture to provide a UserService instance with a temporary users.json."""
|
|
return UserService(users_file)
|
|
|
|
@pytest.fixture
|
|
async def populated_user_service(user_service):
|
|
"""Fixture to provide a UserService instance with some pre-populated users."""
|
|
await user_service.create_user("Admin User", "admin@example.com", "adminpass")
|
|
await user_service.create_user("Parent User", "parent@example.com", "parentpass")
|
|
await user_service.create_user("Child User 1", "child1@example.com", "childpass", "parent@example.com")
|
|
await user_service.create_user("Child User 2", "child2@example.com", "childpass", "parent@example.com")
|
|
return user_service
|
|
|
|
async def test_create_user_success(user_service):
|
|
user = await user_service.create_user("Test User", "test@example.com", "password123")
|
|
assert user is not None
|
|
assert user["email"] == "test@example.com"
|
|
assert await user_service.get_user_by_email("test@example.com") is not None
|
|
assert bcrypt.checkpw(b"password123", user["password"].encode('utf-8'))
|
|
|
|
async def test_create_user_duplicate_email(user_service):
|
|
await user_service.create_user("Test User", "test@example.com", "password123")
|
|
with pytest.raises(ValueError, match="User with this email already exists"):
|
|
await user_service.create_user("Another User", "test@example.com", "anotherpass")
|
|
|
|
async def test_get_all_users(populated_user_service):
|
|
users = await populated_user_service.get_all_users()
|
|
assert len(users) == 4
|
|
emails = {user["email"] for user in users}
|
|
assert "admin@example.com" in emails
|
|
assert "parent@example.com" in emails
|
|
assert "child1@example.com" in emails
|
|
assert "child2@example.com" in emails
|
|
|
|
async def test_get_users_by_parent_email(populated_user_service):
|
|
children = await populated_user_service.get_users_by_parent_email("parent@example.com")
|
|
assert len(children) == 2
|
|
child_emails = {user["email"] for user in children}
|
|
assert "child1@example.com" in child_emails
|
|
assert "child2@example.com" in child_emails
|
|
|
|
no_children = await populated_user_service.get_users_by_parent_email("nonexistent@example.com")
|
|
assert len(no_children) == 0
|
|
|
|
admin_children = await populated_user_service.get_users_by_parent_email("admin@example.com")
|
|
assert len(admin_children) == 0
|
|
|
|
async def test_update_user_non_password_fields(populated_user_service):
|
|
updated_user = await populated_user_service.update_user("admin@example.com", full_name="Administrator", storage_quota_gb=10)
|
|
assert updated_user is not None
|
|
assert updated_user["full_name"] == "Administrator"
|
|
assert updated_user["storage_quota_gb"] == 10
|
|
|
|
retrieved_user = await populated_user_service.get_user_by_email("admin@example.com")
|
|
assert retrieved_user["full_name"] == "Administrator"
|
|
assert retrieved_user["storage_quota_gb"] == 10
|
|
|
|
async def test_update_user_password(populated_user_service):
|
|
updated_user = await populated_user_service.update_user("admin@example.com", password="newadminpass")
|
|
assert updated_user is not None
|
|
assert await populated_user_service.authenticate_user("admin@example.com", "newadminpass")
|
|
assert not await populated_user_service.authenticate_user("admin@example.com", "adminpass")
|
|
|
|
async def test_update_user_nonexistent(user_service):
|
|
updated_user = await user_service.update_user("nonexistent@example.com", full_name="Non Existent")
|
|
assert updated_user is None
|
|
|
|
async def test_delete_user_success(populated_user_service):
|
|
assert await populated_user_service.delete_user("admin@example.com") is True
|
|
assert await populated_user_service.get_user_by_email("admin@example.com") is None
|
|
assert len(await populated_user_service.get_all_users()) == 3
|
|
|
|
async def test_delete_user_nonexistent(user_service):
|
|
assert await user_service.delete_user("nonexistent@example.com") is False
|
|
|
|
async def test_delete_users_by_parent_email_success(populated_user_service):
|
|
deleted_count = await populated_user_service.delete_users_by_parent_email("parent@example.com")
|
|
assert deleted_count == 2
|
|
assert await populated_user_service.get_user_by_email("child1@example.com") is None
|
|
assert await populated_user_service.get_user_by_email("child2@example.com") is None
|
|
assert len(await populated_user_service.get_all_users()) == 2 # Admin and Parent users remain
|
|
|
|
async def test_delete_users_by_parent_email_no_match(user_service):
|
|
deleted_count = await user_service.delete_users_by_parent_email("nonexistent@example.com")
|
|
assert deleted_count == 0
|
|
|
|
async def test_authenticate_user_success(populated_user_service):
|
|
assert await populated_user_service.authenticate_user("admin@example.com", "adminpass") is True
|
|
|
|
async def test_authenticate_user_fail_wrong_password(populated_user_service):
|
|
assert await populated_user_service.authenticate_user("admin@example.com", "wrongpass") is False
|
|
|
|
async def test_authenticate_user_fail_nonexistent_user(user_service):
|
|
assert await user_service.authenticate_user("nonexistent@example.com", "anypass") is False
|
|
|
|
async def test_generate_reset_token_success(populated_user_service):
|
|
token = await populated_user_service.generate_reset_token("admin@example.com")
|
|
assert token is not None
|
|
user = await populated_user_service.get_user_by_email("admin@example.com")
|
|
assert user["reset_token"] == token
|
|
assert user["reset_token_expiry"] is not None
|
|
# Check expiry is in the future
|
|
expiry_dt = datetime.datetime.fromisoformat(user["reset_token_expiry"])
|
|
assert expiry_dt > datetime.datetime.now(datetime.timezone.utc)
|
|
|
|
async def test_generate_reset_token_nonexistent_user(user_service):
|
|
token = await user_service.generate_reset_token("nonexistent@example.com")
|
|
assert token is None
|
|
|
|
async def test_get_user_by_reset_token_valid(populated_user_service):
|
|
token = await populated_user_service.generate_reset_token("admin@example.com")
|
|
user = await populated_user_service.get_user_by_reset_token(token)
|
|
assert user is not None
|
|
assert user["email"] == "admin@example.com"
|
|
|
|
async def test_get_user_by_reset_token_invalid(populated_user_service):
|
|
user = await populated_user_service.get_user_by_reset_token("invalidtoken")
|
|
assert user is None
|
|
|
|
async def test_get_user_by_reset_token_expired(populated_user_service):
|
|
token = await populated_user_service.generate_reset_token("admin@example.com")
|
|
user = await populated_user_service.get_user_by_email("admin@example.com")
|
|
# Manually expire the token
|
|
user["reset_token_expiry"] = (datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(hours=1)).isoformat()
|
|
await populated_user_service._save_users() # Save the expired state
|
|
|
|
user_after_expiry = await populated_user_service.get_user_by_reset_token(token)
|
|
assert user_after_expiry is None
|
|
|
|
async def test_validate_reset_token_success(populated_user_service):
|
|
token = await populated_user_service.generate_reset_token("admin@example.com")
|
|
assert await populated_user_service.validate_reset_token("admin@example.com", token) is True
|
|
|
|
async def test_validate_reset_token_fail_wrong_token(populated_user_service):
|
|
await populated_user_service.generate_reset_token("admin@example.com")
|
|
assert await populated_user_service.validate_reset_token("admin@example.com", "wrongtoken") is False
|
|
|
|
async def test_validate_reset_token_fail_nonexistent_user(user_service):
|
|
assert await user_service.validate_reset_token("nonexistent@example.com", "anytoken") is False
|
|
|
|
async def test_validate_reset_token_fail_expired_token(populated_user_service):
|
|
token = await populated_user_service.generate_reset_token("admin@example.com")
|
|
user = await populated_user_service.get_user_by_email("admin@example.com")
|
|
user["reset_token_expiry"] = (datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(hours=1)).isoformat()
|
|
await populated_user_service._save_users()
|
|
|
|
assert await populated_user_service.validate_reset_token("admin@example.com", token) is False
|
|
|
|
async def test_reset_password_success(populated_user_service):
|
|
token = await populated_user_service.generate_reset_token("admin@example.com")
|
|
assert await populated_user_service.reset_password("admin@example.com", token, "newadminpass") is True
|
|
assert await populated_user_service.authenticate_user("admin@example.com", "newadminpass")
|
|
user = await populated_user_service.get_user_by_email("admin@example.com")
|
|
assert user["reset_token"] is None
|
|
assert user["reset_token_expiry"] is None
|
|
|
|
async def test_reset_password_fail_invalid_token(populated_user_service):
|
|
await populated_user_service.generate_reset_token("admin@example.com")
|
|
assert await populated_user_service.reset_password("admin@example.com", "invalidtoken", "newadminpass") is False
|
|
assert await populated_user_service.authenticate_user("admin@example.com", "adminpass") # Password should not change
|
|
|
|
async def test_reset_password_fail_nonexistent_user(user_service):
|
|
# Even if a token was somehow generated for a nonexistent user (which shouldn't happen),
|
|
# reset_password should fail.
|
|
assert await user_service.reset_password("nonexistent@example.com", "anytoken", "newpass") is False
|
|
|
|
async def test_update_user_quota_success(populated_user_service):
|
|
await populated_user_service.update_user_quota("admin@example.com", 20.5)
|
|
user = await populated_user_service.get_user_by_email("admin@example.com")
|
|
assert user["storage_quota_gb"] == 20.5
|
|
|
|
async def test_update_user_quota_nonexistent_user(user_service):
|
|
with pytest.raises(ValueError, match="User not found"):
|
|
await user_service.update_user_quota("nonexistent@example.com", 100)
|