FossilRepo

fossilrepo / tests / test_notification_prefs.py
Blame History Raw 245 lines
1
from unittest.mock import patch
2
3
import pytest
4
from django.contrib.auth.models import User
5
6
from fossil.notifications import Notification, NotificationPreference
7
8
# --- NotificationPreference Model Tests ---
9
10
11
@pytest.mark.django_db
12
class TestNotificationPreferenceModel:
13
def test_create_preference(self, admin_user):
14
pref = NotificationPreference.objects.create(user=admin_user)
15
assert pref.pk is not None
16
assert pref.delivery_mode == "immediate"
17
assert pref.notify_checkins is True
18
assert pref.notify_tickets is True
19
assert pref.notify_wiki is True
20
assert pref.notify_releases is True
21
assert pref.notify_forum is False
22
23
def test_str_repr(self, admin_user):
24
pref = NotificationPreference.objects.create(user=admin_user, delivery_mode="daily")
25
assert str(pref) == "admin: daily"
26
27
def test_one_to_one_constraint(self, admin_user):
28
NotificationPreference.objects.create(user=admin_user)
29
from django.db import IntegrityError
30
31
with pytest.raises(IntegrityError):
32
NotificationPreference.objects.create(user=admin_user)
33
34
def test_delivery_mode_choices(self, admin_user):
35
for mode in ["immediate", "daily", "weekly", "off"]:
36
pref, _ = NotificationPreference.objects.update_or_create(user=admin_user, defaults={"delivery_mode": mode})
37
pref.refresh_from_db()
38
assert pref.delivery_mode == mode
39
40
41
# --- Notification Preferences View Tests ---
42
43
44
@pytest.mark.django_db
45
class TestNotificationPreferencesView:
46
def test_get_creates_default_prefs(self, admin_client, admin_user):
47
assert not NotificationPreference.objects.filter(user=admin_user).exists()
48
response = admin_client.get("/auth/notifications/")
49
assert response.status_code == 200
50
assert "Notification Preferences" in response.content.decode()
51
assert NotificationPreference.objects.filter(user=admin_user).exists()
52
53
def test_get_renders_existing_prefs(self, admin_client, admin_user):
54
NotificationPreference.objects.create(user=admin_user, delivery_mode="daily", notify_forum=True)
55
response = admin_client.get("/auth/notifications/")
56
assert response.status_code == 200
57
content = response.content.decode()
58
assert "Notification Preferences" in content
59
60
def test_post_updates_delivery_mode(self, admin_client, admin_user):
61
NotificationPreference.objects.create(user=admin_user)
62
response = admin_client.post(
63
"/auth/notifications/",
64
{
65
"delivery_mode": "daily",
66
"notify_checkins": "on",
67
"notify_tickets": "on",
68
},
69
)
70
assert response.status_code == 302
71
pref = NotificationPreference.objects.get(user=admin_user)
72
assert pref.delivery_mode == "daily"
73
assert pref.notify_checkins is True
74
assert pref.notify_tickets is True
75
assert pref.notify_wiki is False
76
assert pref.notify_releases is False
77
assert pref.notify_forum is False
78
79
def test_post_updates_event_toggles(self, admin_client, admin_user):
80
NotificationPreference.objects.create(user=admin_user)
81
response = admin_client.post(
82
"/auth/notifications/",
83
{
84
"delivery_mode": "weekly",
85
"notify_checkins": "on",
86
"notify_tickets": "on",
87
"notify_wiki": "on",
88
"notify_releases": "on",
89
"notify_forum": "on",
90
},
91
)
92
assert response.status_code == 302
93
pref = NotificationPreference.objects.get(user=admin_user)
94
assert pref.delivery_mode == "weekly"
95
assert pref.notify_checkins is True
96
assert pref.notify_tickets is True
97
assert pref.notify_wiki is True
98
assert pref.notify_releases is True
99
assert pref.notify_forum is True
100
101
def test_post_turn_off(self, admin_client, admin_user):
102
NotificationPreference.objects.create(user=admin_user, delivery_mode="daily")
103
response = admin_client.post(
104
"/auth/notifications/",
105
{
106
"delivery_mode": "off",
107
},
108
)
109
assert response.status_code == 302
110
pref = NotificationPreference.objects.get(user=admin_user)
111
assert pref.delivery_mode == "off"
112
# All unchecked checkboxes default to False
113
assert pref.notify_checkins is False
114
assert pref.notify_tickets is False
115
116
def test_denied_for_anon(self, client):
117
response = client.get("/auth/notifications/")
118
assert response.status_code == 302 # redirect to login
119
120
121
# --- Digest Task Tests ---
122
123
124
@pytest.mark.django_db
125
class TestSendDigestTask:
126
@pytest.fixture
127
def daily_user(self, db):
128
user = User.objects.create_user(username="dailyuser", email="[email protected]", password="testpass123")
129
NotificationPreference.objects.create(user=user, delivery_mode="daily")
130
return user
131
132
@pytest.fixture
133
def weekly_user(self, db):
134
user = User.objects.create_user(username="weeklyuser", email="[email protected]", password="testpass123")
135
NotificationPreference.objects.create(user=user, delivery_mode="weekly")
136
return user
137
138
@pytest.fixture
139
def immediate_user(self, db):
140
user = User.objects.create_user(username="immediateuser", email="[email protected]", password="testpass123")
141
NotificationPreference.objects.create(user=user, delivery_mode="immediate")
142
return user
143
144
def test_daily_digest_sends_email(self, daily_user, sample_project):
145
# Create unread notifications
146
for i in range(3):
147
Notification.objects.create(
148
user=daily_user,
149
project=sample_project,
150
event_type="checkin",
151
title=f"Commit #{i}",
152
)
153
154
from fossil.tasks import send_digest
155
156
with patch("django.core.mail.send_mail") as mock_send:
157
send_digest.apply(kwargs={"mode": "daily"})
158
159
mock_send.assert_called_once()
160
call_kwargs = mock_send.call_args
161
assert "Daily" in call_kwargs[1]["subject"] or "Daily" in call_kwargs[0][0]
162
assert daily_user.email in (call_kwargs[1].get("recipient_list") or call_kwargs[0][3])
163
164
# Notifications marked as read
165
assert Notification.objects.filter(user=daily_user, read=False).count() == 0
166
167
def test_weekly_digest_sends_email(self, weekly_user, sample_project):
168
Notification.objects.create(
169
user=weekly_user,
170
project=sample_project,
171
event_type="ticket",
172
title="New ticket",
173
)
174
175
from fossil.tasks import send_digest
176
177
with patch("django.core.mail.send_mail") as mock_send:
178
send_digest.apply(kwargs={"mode": "weekly"})
179
180
mock_send.assert_called_once()
181
182
def test_no_email_for_immediate_users(self, immediate_user, sample_project):
183
Notification.objects.create(
184
user=immediate_user,
185
project=sample_project,
186
event_type="checkin",
187
title="Commit",
188
)
189
190
from fossil.tasks import send_digest
191
192
with patch("django.core.mail.send_mail") as mock_send:
193
send_digest.apply(kwargs={"mode": "daily"})
194
195
mock_send.assert_not_called()
196
197
def test_no_email_when_no_unread(self, daily_user, sample_project):
198
# Create read notifications
199
Notification.objects.create(
200
user=daily_user,
201
project=sample_project,
202
event_type="checkin",
203
title="Old commit",
204
read=True,
205
)
206
207
from fossil.tasks import send_digest
208
209
with patch("django.core.mail.send_mail") as mock_send:
210
send_digest.apply(kwargs={"mode": "daily"})
211
212
mock_send.assert_not_called()
213
214
def test_digest_limits_to_50_notifications(self, daily_user, sample_project):
215
for i in range(55):
216
Notification.objects.create(
217
user=daily_user,
218
project=sample_project,
219
event_type="checkin",
220
title=f"Commit #{i}",
221
)
222
223
from fossil.tasks import send_digest
224
225
with patch("django.core.mail.send_mail") as mock_send:
226
send_digest.apply(kwargs={"mode": "daily"})
227
228
mock_send.assert_called_once()
229
call_args = mock_send.call_args
230
message = call_args[1].get("message") or call_args[0][1]
231
assert "55 new notifications" in message
232
assert "and 5 more" in message
233
234
# All 55 marked as read
235
assert Notification.objects.filter(user=daily_user, read=False).count() == 0
236
237
def test_digest_no_users_with_mode(self):
238
"""When no users have the requested delivery mode, task completes without error."""
239
from fossil.tasks import send_digest
240
241
with patch("django.core.mail.send_mail") as mock_send:
242
send_digest.apply(kwargs={"mode": "daily"})
243
244
mock_send.assert_not_called()
245

Keyboard Shortcuts

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