Files

139 lines
4.7 KiB
Python
Raw Permalink Normal View History

"""Tests for the DSAR worker job (G1 DSGVO: Art. 15/17).
Proves the previously missing "process_dsar" job works end-to-end:
- access: collects profile + contacts + audit_log + notifications
- deletion: soft-deletes contacts, hard-deletes notifications, anonymizes
and deactivates the account, writes a dsar_erasure audit entry
"""
from __future__ import annotations
import uuid
import pytest
import pytest_asyncio
from sqlalchemy import select as sa_select
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
from app.core.db import reset_engine_for_testing
from app.core.jobs import _dsar_collect_user_data, _dsar_execute_deletion, process_dsar
from app.models.audit import AuditLog
from app.models.contact import Contact
from app.models.notification import Notification
from app.models.user import User
from tests.conftest import seed_tenant_and_users
@pytest_asyncio.fixture
async def dsar_session(engine) -> AsyncSession:
reset_engine_for_testing(engine)
sf = async_sessionmaker(bind=engine, expire_on_commit=False, class_=AsyncSession)
async with sf() as session:
yield session
await session.rollback()
def test_process_dsar_registered():
"""The job is registered so enqueue_job('process_dsar') can find it."""
from app.core.job_registry import get_job
assert get_job("process_dsar") is not None
@pytest.mark.asyncio
async def test_dsar_access_collects_all_categories(dsar_session: AsyncSession):
"""Art. 15: collect_user_data returns all promised categories."""
seed = await seed_tenant_and_users(dsar_session)
data = await _dsar_collect_user_data(
dsar_session,
str(seed["tenant_a"].id),
str(seed["admin_a"].id),
)
assert data["legal_basis"]
for category in ("profile", "contacts", "audit_log", "notifications"):
assert category in data["data"], f"missing category {category}"
@pytest.mark.asyncio
async def test_dsar_deletion_anonymizes_and_soft_deletes(dsar_session: AsyncSession):
"""Art. 17: contacts soft-deleted, notifications gone, user anonymized."""
seed = await seed_tenant_and_users(dsar_session)
uid = seed["admin_a"].id
tid = seed["tenant_a"].id
# Fixture: one contact + one notification owned by admin_a
contact = Contact(
id=uuid.uuid4(), tenant_id=tid, owner_id=uid,
type="person", displayname="To Erase", email_1="erase@test.local",
firstname="Era", surname="SeMe",
discount_crew=0, discount_transport=0, discount_rental=0,
discount_sale=0, discount_subrent=0, discount_total=0,
)
notification = Notification(
id=uuid.uuid4(), tenant_id=tid, owner_id=uid,
user_id=uid,
type="test",
title="to erase",
)
dsar_session.add_all([contact, notification])
await dsar_session.commit()
counts = await _dsar_execute_deletion(dsar_session, str(tid), str(uid))
await dsar_session.commit()
assert counts["contacts_soft_deleted"] == 1
assert counts["notifications_deleted"] == 1
assert counts["user_anonymized"] == 1
# Verify persisted state (fresh query, bypassing identity map)
dsar_session.expunge_all()
erased_contact = (
await dsar_session.execute(sa_select(Contact).where(Contact.id == contact.id))
).scalar_one()
assert erased_contact.deleted_at is not None
remaining_notifications = (
await dsar_session.execute(
sa_select(Notification).where(Notification.owner_id == uid)
)
).scalars().all()
assert len(remaining_notifications) == 0
erased_user = (
await dsar_session.execute(sa_select(User).where(User.id == uid))
).scalar_one()
assert erased_user.is_active is False
assert erased_user.name == "[gelöscht gemäß DSGVO Art. 17]"
assert "anonymized.invalid" in erased_user.email
# Audit entry written
audits = (
await dsar_session.execute(
sa_select(AuditLog).where(AuditLog.action == "dsar_erasure")
)
).scalars().all()
assert len(audits) >= 1
@pytest.mark.asyncio
async def test_process_dsar_dispatches_by_type(dsar_session: AsyncSession):
"""process_dsar dispatches by request_type without raising."""
seed = await seed_tenant_and_users(dsar_session)
result = await process_dsar(
{},
user_id=str(seed["admin_a"].id),
tenant_id=str(seed["tenant_a"].id),
request_type="access",
)
assert result["status"] == "completed"
assert "categories" in result
result = await process_dsar(
{},
user_id=str(seed["editor_a"].id),
tenant_id=str(seed["tenant_a"].id),
request_type="unknown_type_xyz",
)
assert result["status"] == "unknown_type"