test(backend): convert existing app suites to unittest
This commit is contained in:
@@ -1,181 +1,161 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
import pytest
|
||||
from auditlog.models import LogEntry
|
||||
from rest_framework_simplejwt.tokens import AccessToken
|
||||
from rest_framework.test import APIClient
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from apps.reports.models import ReportExportJob
|
||||
from apps.users.models import User
|
||||
from apps.workspaces.models import Workspace, WorkspaceMembership
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def api_client():
|
||||
return APIClient()
|
||||
class WorkspaceLogViewTests(APITestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.owner = cls._user(1)
|
||||
cls.admin = cls._user(2)
|
||||
cls.member = cls._user(3)
|
||||
cls.outsider = cls._user(4)
|
||||
|
||||
cls.workspace = Workspace.objects.create(
|
||||
name="Logs WS",
|
||||
description="",
|
||||
owner=cls.owner,
|
||||
)
|
||||
WorkspaceMembership.objects.create(
|
||||
workspace=cls.workspace,
|
||||
user=cls.admin,
|
||||
role=WorkspaceMembership.Role.ADMIN,
|
||||
is_active=True,
|
||||
)
|
||||
WorkspaceMembership.objects.create(
|
||||
workspace=cls.workspace,
|
||||
user=cls.member,
|
||||
role=WorkspaceMembership.Role.MEMBER,
|
||||
is_active=True,
|
||||
)
|
||||
|
||||
def _user(index: int) -> User:
|
||||
return User.objects.create_user(
|
||||
mobile=f"093355500{index:02d}",
|
||||
password="secret123",
|
||||
first_name=f"Log{index}",
|
||||
last_name="User",
|
||||
)
|
||||
@staticmethod
|
||||
def _user(index):
|
||||
return User.objects.create_user(
|
||||
mobile=f"093355500{index:02d}",
|
||||
password="secret123",
|
||||
first_name=f"Log{index}",
|
||||
last_name="User",
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _auth_headers(user):
|
||||
token = str(AccessToken.for_user(user))
|
||||
return {"HTTP_AUTHORIZATION": f"Bearer {token}"}
|
||||
|
||||
@pytest.fixture()
|
||||
def owner(db):
|
||||
return _user(1)
|
||||
def _create_tag(self, user, *, name="Audit Tag"):
|
||||
return self.client.post(
|
||||
"/api/tags/",
|
||||
{
|
||||
"workspace_id": str(self.workspace.id),
|
||||
"name": name,
|
||||
"color": "#123456",
|
||||
},
|
||||
format="json",
|
||||
**self._auth_headers(user),
|
||||
)
|
||||
|
||||
def test_owner_and_admin_can_list_workspace_logs(self):
|
||||
create_response = self._create_tag(self.owner)
|
||||
self.assertEqual(create_response.status_code, 201)
|
||||
|
||||
@pytest.fixture()
|
||||
def admin(db):
|
||||
return _user(2)
|
||||
owner_response = self.client.get(
|
||||
f"/api/logs/?workspace={self.workspace.id}",
|
||||
**self._auth_headers(self.owner),
|
||||
)
|
||||
admin_response = self.client.get(
|
||||
f"/api/logs/?workspace={self.workspace.id}",
|
||||
**self._auth_headers(self.admin),
|
||||
)
|
||||
|
||||
self.assertEqual(owner_response.status_code, 200)
|
||||
self.assertEqual(admin_response.status_code, 200)
|
||||
self.assertEqual(owner_response.data["items"][0]["section"], "tags")
|
||||
|
||||
@pytest.fixture()
|
||||
def member(db):
|
||||
return _user(3)
|
||||
def test_member_and_non_member_cannot_list_workspace_logs(self):
|
||||
self._create_tag(self.owner)
|
||||
|
||||
member_response = self.client.get(
|
||||
f"/api/logs/?workspace={self.workspace.id}",
|
||||
**self._auth_headers(self.member),
|
||||
)
|
||||
outsider_response = self.client.get(
|
||||
f"/api/logs/?workspace={self.workspace.id}",
|
||||
**self._auth_headers(self.outsider),
|
||||
)
|
||||
|
||||
@pytest.fixture()
|
||||
def outsider(db):
|
||||
return _user(4)
|
||||
self.assertEqual(member_response.status_code, 403)
|
||||
self.assertEqual(outsider_response.status_code, 403)
|
||||
|
||||
def test_jwt_authenticated_writes_capture_actor_and_workspace_metadata(self):
|
||||
response = self._create_tag(self.owner, name="JWT Tag")
|
||||
self.assertEqual(response.status_code, 201)
|
||||
|
||||
@pytest.fixture()
|
||||
def workspace(owner, admin, member):
|
||||
workspace = Workspace.objects.create(name="Logs WS", description="", owner=owner)
|
||||
WorkspaceMembership.objects.create(
|
||||
workspace=workspace,
|
||||
user=admin,
|
||||
role=WorkspaceMembership.Role.ADMIN,
|
||||
is_active=True,
|
||||
)
|
||||
WorkspaceMembership.objects.create(
|
||||
workspace=workspace,
|
||||
user=member,
|
||||
role=WorkspaceMembership.Role.MEMBER,
|
||||
is_active=True,
|
||||
)
|
||||
return workspace
|
||||
log_entry = LogEntry.objects.filter(content_type__app_label="tags").latest(
|
||||
"timestamp"
|
||||
)
|
||||
|
||||
self.assertEqual(log_entry.actor_id, self.owner.id)
|
||||
self.assertEqual(log_entry.additional_data["workspace_id"], str(self.workspace.id))
|
||||
self.assertEqual(log_entry.additional_data["section"], "tags")
|
||||
|
||||
def _auth_headers(user: User) -> dict:
|
||||
token = str(AccessToken.for_user(user))
|
||||
return {"HTTP_AUTHORIZATION": f"Bearer {token}"}
|
||||
def test_logs_support_section_filter_and_detail(self):
|
||||
tag_response = self._create_tag(self.owner, name="Filtered Tag")
|
||||
self.assertEqual(tag_response.status_code, 201)
|
||||
|
||||
list_response = self.client.get(
|
||||
f"/api/logs/?workspace={self.workspace.id}§ion=tags",
|
||||
**self._auth_headers(self.owner),
|
||||
)
|
||||
|
||||
def _create_tag(client: APIClient, user: User, workspace: Workspace, *, name="Audit Tag"):
|
||||
return client.post(
|
||||
"/api/tags/",
|
||||
{"workspace_id": str(workspace.id), "name": name, "color": "#123456"},
|
||||
format="json",
|
||||
**_auth_headers(user),
|
||||
)
|
||||
self.assertEqual(list_response.status_code, 200)
|
||||
self.assertTrue(list_response.data["items"])
|
||||
log_id = list_response.data["items"][0]["id"]
|
||||
|
||||
detail_response = self.client.get(
|
||||
f"/api/logs/{log_id}/",
|
||||
**self._auth_headers(self.owner),
|
||||
)
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_owner_and_admin_can_list_workspace_logs(api_client, owner, admin, workspace):
|
||||
create_response = _create_tag(api_client, owner, workspace)
|
||||
assert create_response.status_code == 201
|
||||
self.assertEqual(detail_response.status_code, 200)
|
||||
self.assertEqual(detail_response.data["target"]["name"], "Filtered Tag")
|
||||
self.assertTrue(detail_response.data["changes"])
|
||||
|
||||
owner_response = api_client.get(
|
||||
f"/api/logs/?workspace={workspace.id}",
|
||||
**_auth_headers(owner),
|
||||
)
|
||||
admin_response = api_client.get(
|
||||
f"/api/logs/?workspace={workspace.id}",
|
||||
**_auth_headers(admin),
|
||||
)
|
||||
def test_soft_delete_and_actorless_background_logs_are_filtered(self):
|
||||
create_response = self._create_tag(self.owner, name="Delete Me")
|
||||
self.assertEqual(create_response.status_code, 201)
|
||||
tag_id = create_response.data["id"]
|
||||
|
||||
assert owner_response.status_code == 200
|
||||
assert admin_response.status_code == 200
|
||||
assert owner_response.data["items"][0]["section"] == "tags"
|
||||
delete_response = self.client.delete(
|
||||
f"/api/tags/{tag_id}/",
|
||||
**self._auth_headers(self.owner),
|
||||
)
|
||||
self.assertEqual(delete_response.status_code, 204)
|
||||
|
||||
ReportExportJob.objects.create(
|
||||
requesting_user=self.owner,
|
||||
workspace=self.workspace,
|
||||
export_type=ReportExportJob.ExportType.PDF,
|
||||
filters={"workspace": str(self.workspace.id)},
|
||||
status=ReportExportJob.Status.PENDING,
|
||||
)
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_member_and_non_member_cannot_list_workspace_logs(api_client, owner, member, outsider, workspace):
|
||||
_create_tag(api_client, owner, workspace)
|
||||
|
||||
member_response = api_client.get(
|
||||
f"/api/logs/?workspace={workspace.id}",
|
||||
**_auth_headers(member),
|
||||
)
|
||||
outsider_response = api_client.get(
|
||||
f"/api/logs/?workspace={workspace.id}",
|
||||
**_auth_headers(outsider),
|
||||
)
|
||||
|
||||
assert member_response.status_code == 403
|
||||
assert outsider_response.status_code == 403
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_jwt_authenticated_writes_capture_actor_and_workspace_metadata(api_client, owner, workspace):
|
||||
response = _create_tag(api_client, owner, workspace, name="JWT Tag")
|
||||
assert response.status_code == 201
|
||||
|
||||
log_entry = LogEntry.objects.filter(content_type__app_label="tags").latest("timestamp")
|
||||
|
||||
assert log_entry.actor_id == owner.id
|
||||
assert log_entry.additional_data["workspace_id"] == str(workspace.id)
|
||||
assert log_entry.additional_data["section"] == "tags"
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_logs_support_section_filter_and_detail(api_client, owner, workspace):
|
||||
tag_response = _create_tag(api_client, owner, workspace, name="Filtered Tag")
|
||||
assert tag_response.status_code == 201
|
||||
|
||||
list_response = api_client.get(
|
||||
f"/api/logs/?workspace={workspace.id}§ion=tags",
|
||||
**_auth_headers(owner),
|
||||
)
|
||||
|
||||
assert list_response.status_code == 200
|
||||
assert list_response.data["items"]
|
||||
log_id = list_response.data["items"][0]["id"]
|
||||
|
||||
detail_response = api_client.get(
|
||||
f"/api/logs/{log_id}/",
|
||||
**_auth_headers(owner),
|
||||
)
|
||||
|
||||
assert detail_response.status_code == 200
|
||||
assert detail_response.data["target"]["name"] == "Filtered Tag"
|
||||
assert detail_response.data["changes"]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_soft_delete_and_actorless_background_logs_are_filtered(api_client, owner, workspace):
|
||||
create_response = _create_tag(api_client, owner, workspace, name="Delete Me")
|
||||
assert create_response.status_code == 201
|
||||
tag_id = create_response.data["id"]
|
||||
|
||||
delete_response = api_client.delete(
|
||||
f"/api/tags/{tag_id}/",
|
||||
**_auth_headers(owner),
|
||||
)
|
||||
assert delete_response.status_code == 204
|
||||
|
||||
ReportExportJob.objects.create(
|
||||
requesting_user=owner,
|
||||
workspace=workspace,
|
||||
export_type=ReportExportJob.ExportType.PDF,
|
||||
filters={"workspace": str(workspace.id)},
|
||||
status=ReportExportJob.Status.PENDING,
|
||||
)
|
||||
|
||||
response = api_client.get(
|
||||
f"/api/logs/?workspace={workspace.id}&event=delete",
|
||||
**_auth_headers(owner),
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert any(item["event"] == "delete" and item["section"] == "tags" for item in response.data["items"])
|
||||
assert all(item["section"] != "report_exports" for item in response.data["items"])
|
||||
response = self.client.get(
|
||||
f"/api/logs/?workspace={self.workspace.id}&event=delete",
|
||||
**self._auth_headers(self.owner),
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTrue(
|
||||
any(
|
||||
item["event"] == "delete" and item["section"] == "tags"
|
||||
for item in response.data["items"]
|
||||
)
|
||||
)
|
||||
self.assertTrue(
|
||||
all(item["section"] != "report_exports" for item in response.data["items"])
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user