Files

195 lines
6.1 KiB
Python

import uuid
import pytest
from sqlalchemy import text
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.roles import AccountKind, Role
from app.repositories.user import UserRepository
pytestmark = pytest.mark.integration
def adresse() -> str:
return f"compte-{uuid.uuid4().hex[:12]}@enervision.fr"
async def test_create_normalises_the_email_to_lower_case(session: AsyncSession) -> None:
depot = UserRepository(session)
saisie = adresse().upper()
compte = await depot.create(email=saisie, password_hash="$argon2id$x", role=Role.LECTEUR)
enregistre = compte.email
await session.rollback()
assert enregistre == saisie.lower()
async def test_the_database_refuses_an_email_written_in_upper_case(
session: AsyncSession,
) -> None:
saisie = adresse().upper()
requete = text(
"insert into app_user (email, password_hash, role) values (:e, '$argon2id$x', 'lecteur')"
)
with pytest.raises(IntegrityError):
await session.execute(requete, {"e": saisie})
await session.rollback()
async def test_the_database_refuses_two_accounts_sharing_an_email(
session: AsyncSession,
) -> None:
depot = UserRepository(session)
saisie = adresse()
await depot.create(email=saisie, password_hash="$argon2id$x", role=Role.LECTEUR)
with pytest.raises(IntegrityError):
await depot.create(email=saisie, password_hash="$argon2id$y", role=Role.ADMIN)
await session.rollback()
async def test_get_by_email_is_case_insensitive(session: AsyncSession) -> None:
depot = UserRepository(session)
saisie = adresse()
await depot.create(email=saisie, password_hash="$argon2id$x", role=Role.OPERATEUR)
trouve = await depot.get_by_email(saisie.upper())
role = trouve.role if trouve else None
await session.rollback()
assert role == Role.OPERATEUR.value
async def test_get_by_email_returns_nothing_for_an_unknown_address(
session: AsyncSession,
) -> None:
trouve = await UserRepository(session).get_by_email(adresse())
assert trouve is None
async def test_set_role_moves_the_credentials_marker_forward(session: AsyncSession) -> None:
depot = UserRepository(session)
compte = await depot.create(email=adresse(), password_hash="$argon2id$x", role=Role.LECTEUR)
avant = compte.credentials_changed_at
await depot.set_role(compte.id, Role.ADMIN)
await session.refresh(compte)
apres, role = compte.credentials_changed_at, compte.role
await session.rollback()
assert role == Role.ADMIN.value
assert apres > avant
async def test_set_active_moves_the_credentials_marker_forward(session: AsyncSession) -> None:
depot = UserRepository(session)
compte = await depot.create(email=adresse(), password_hash="$argon2id$x", role=Role.LECTEUR)
avant = compte.credentials_changed_at
await depot.set_active(compte.id, is_active=False)
await session.refresh(compte)
apres, actif = compte.credentials_changed_at, compte.is_active
await session.rollback()
assert actif is False
assert apres > avant
async def test_rehash_password_leaves_the_credentials_marker_untouched(
session: AsyncSession,
) -> None:
depot = UserRepository(session)
compte = await depot.create(email=adresse(), password_hash="$argon2id$x", role=Role.LECTEUR)
avant = compte.credentials_changed_at
await depot.rehash_password(compte.id, "$argon2id$plus-recent")
await session.refresh(compte)
apres, empreinte = compte.credentials_changed_at, compte.password_hash
await session.rollback()
assert empreinte == "$argon2id$plus-recent"
assert apres == avant
async def test_update_password_moves_the_credentials_marker_forward(
session: AsyncSession,
) -> None:
depot = UserRepository(session)
compte = await depot.create(email=adresse(), password_hash="$argon2id$x", role=Role.LECTEUR)
avant = compte.credentials_changed_at
await depot.update_password(compte.id, "$argon2id$neuf", must_change_password=False)
await session.refresh(compte)
apres = compte.credentials_changed_at
await session.rollback()
assert apres > avant
async def test_touch_last_login_records_the_connection_date(session: AsyncSession) -> None:
depot = UserRepository(session)
compte = await depot.create(email=adresse(), password_hash="$argon2id$x", role=Role.LECTEUR)
await depot.touch_last_login(compte.id)
await session.refresh(compte)
date = compte.last_login_at
await session.rollback()
assert date is not None
async def test_count_active_admins_only_counts_enabled_administrators(
session: AsyncSession,
) -> None:
depot = UserRepository(session)
depart = await depot.count_active_admins()
await depot.create(email=adresse(), password_hash="$argon2id$x", role=Role.ADMIN)
desactive = await depot.create(email=adresse(), password_hash="$argon2id$x", role=Role.ADMIN)
await depot.set_active(desactive.id, is_active=False)
total = await depot.count_active_admins()
await session.rollback()
assert total == depart + 1
async def test_create_accepts_a_service_account(session: AsyncSession) -> None:
depot = UserRepository(session)
compte = await depot.create(
email=adresse(),
password_hash="$argon2id$x",
role=Role.OPERATEUR,
kind=AccountKind.SERVICE,
)
nature = compte.kind
await session.rollback()
assert nature == AccountKind.SERVICE.value
async def test_list_all_returns_the_accounts_sorted_by_email(session: AsyncSession) -> None:
depot = UserRepository(session)
await depot.create(email=f"zz-{adresse()}", password_hash="$argon2id$x", role=Role.LECTEUR)
await depot.create(email=f"aa-{adresse()}", password_hash="$argon2id$x", role=Role.LECTEUR)
comptes = await depot.list_all()
emails = [compte.email for compte in comptes]
await session.rollback()
assert emails == sorted(emails)
async def test_get_by_id_returns_nothing_for_an_unknown_identifier(
session: AsyncSession,
) -> None:
trouve = await UserRepository(session).get_by_id(uuid.uuid4())
assert trouve is None