FossilRepo

fossilrepo / tests / test_audit_log.py
Blame History Raw 122 lines
1
"""Tests for Unified Audit Log: view, permissions, filtering."""
2
3
import pytest
4
from django.contrib.auth.models import Group, Permission
5
6
from organization.models import Team
7
from projects.models import Project
8
9
10
@pytest.fixture
11
def org_admin_user(db):
12
"""User with ORGANIZATION_CHANGE permission but not superuser."""
13
user = __import__("django.contrib.auth.models", fromlist=["User"]).User.objects.create_user(
14
username="orgadmin", email="[email protected]", password="testpass123"
15
)
16
group, _ = Group.objects.get_or_create(name="OrgAdmins")
17
perms = Permission.objects.filter(
18
content_type__app_label="organization",
19
)
20
group.permissions.set(perms)
21
user.groups.add(group)
22
return user
23
24
25
@pytest.fixture
26
def org_admin_client(client, org_admin_user):
27
client.login(username="orgadmin", password="testpass123")
28
return client
29
30
31
# --- Access Control ---
32
33
34
@pytest.mark.django_db
35
class TestAuditLogAccess:
36
def test_audit_log_accessible_to_superuser(self, admin_client):
37
response = admin_client.get("/settings/audit/")
38
assert response.status_code == 200
39
assert "Audit Log" in response.content.decode()
40
41
def test_audit_log_accessible_to_org_admin(self, org_admin_client):
42
response = org_admin_client.get("/settings/audit/")
43
assert response.status_code == 200
44
45
def test_audit_log_denied_for_viewer(self, viewer_client):
46
response = viewer_client.get("/settings/audit/")
47
assert response.status_code == 403
48
49
def test_audit_log_denied_for_no_perm(self, no_perm_client):
50
response = no_perm_client.get("/settings/audit/")
51
assert response.status_code == 403
52
53
def test_audit_log_denied_for_anon(self, client):
54
response = client.get("/settings/audit/")
55
assert response.status_code == 302 # Redirect to login
56
57
58
# --- Content ---
59
60
61
@pytest.mark.django_db
62
class TestAuditLogContent:
63
def test_shows_project_history(self, admin_client, admin_user, org):
64
Project.objects.create(name="Audit Test Project", organization=org, created_by=admin_user)
65
response = admin_client.get("/settings/audit/")
66
content = response.content.decode()
67
assert "Audit Test Project" in content
68
assert "Created" in content
69
70
def test_shows_organization_history(self, admin_client, org):
71
response = admin_client.get("/settings/audit/")
72
content = response.content.decode()
73
assert "Organization" in content
74
75
def test_shows_team_history(self, admin_client, admin_user, org):
76
Team.objects.create(name="Audit Test Team", organization=org, created_by=admin_user)
77
response = admin_client.get("/settings/audit/")
78
content = response.content.decode()
79
assert "Audit Test Team" in content
80
81
def test_filter_by_model_type(self, admin_client, admin_user, org):
82
Project.objects.create(name="Filter Test", organization=org, created_by=admin_user)
83
Team.objects.create(name="Should Not Show", organization=org, created_by=admin_user)
84
response = admin_client.get("/settings/audit/?model=Project")
85
content = response.content.decode()
86
assert "Filter Test" in content
87
assert "Should Not Show" not in content
88
89
def test_filter_shows_all_when_no_filter(self, admin_client, admin_user, org):
90
Project.objects.create(name="Project Entry", organization=org, created_by=admin_user)
91
Team.objects.create(name="Team Entry", organization=org, created_by=admin_user)
92
response = admin_client.get("/settings/audit/")
93
content = response.content.decode()
94
assert "Project Entry" in content
95
assert "Team Entry" in content
96
97
def test_audit_log_entries_sorted_by_date(self, admin_client, admin_user, org):
98
Project.objects.create(name="First Project", organization=org, created_by=admin_user)
99
Project.objects.create(name="Second Project", organization=org, created_by=admin_user)
100
response = admin_client.get("/settings/audit/?model=Project")
101
entries = response.context["entries"]
102
# Most recent first
103
project_entries = [e for e in entries if e["model"] == "Project"]
104
dates = [e["date"] for e in project_entries]
105
assert dates == sorted(dates, reverse=True)
106
107
def test_available_models_in_context(self, admin_client):
108
response = admin_client.get("/settings/audit/")
109
assert "available_models" in response.context
110
assert "Project" in response.context["available_models"]
111
assert "Organization" in response.context["available_models"]
112
assert "Team" in response.context["available_models"]
113
assert "FossilRepository" in response.context["available_models"]
114
115
def test_audit_log_sidebar_link_for_superuser(self, admin_client):
116
response = admin_client.get("/dashboard/")
117
assert "/settings/audit/" in response.content.decode()
118
119
def test_audit_log_sidebar_link_hidden_for_viewer(self, viewer_client):
120
response = viewer_client.get("/dashboard/")
121
assert "/settings/audit/" not in response.content.decode()
122

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button