Coverage for website/members/tests/test_services.py: 100.00%
104 statements
« prev ^ index » next coverage.py v7.6.7, created at 2025-08-14 10:31 +0000
« prev ^ index » next coverage.py v7.6.7, created at 2025-08-14 10:31 +0000
1from datetime import date
2from unittest import mock
4from django.test import TestCase, override_settings
5from django.utils import timezone
7from freezegun import freeze_time
9from members import services
10from members.models import EmailChange, Member, Membership, Profile
11from members.services import gen_stats_year
14@freeze_time("2020-01-01")
15class StatisticsTest(TestCase):
16 @classmethod
17 def setUpTestData(cls):
18 for i in range(10):
19 Member.objects.create(id=i, username=i)
21 Membership.objects.create(
22 user_id=i,
23 type=Membership.MEMBER,
24 since=date(year=(2017 if i < 5 else 2018), month=1, day=1),
25 )
27 def test_gen_stats_year(self):
28 result = gen_stats_year()
30 # We should have 5 members in 2017 and 10 members in 2018
31 self.assertEqual([0, 0, 5, 10], result["datasets"][0]["data"][:4])
34@override_settings(SUSPEND_SIGNALS=True)
35class EmailChangeTest(TestCase):
36 fixtures = ["members.json"]
38 @classmethod
39 def setUpTestData(cls):
40 # Add 10 members with default membership
41 cls.member = Member.objects.get(pk=2)
43 def setUp(self):
44 self.member.refresh_from_db()
46 def test_verify_email_change(self):
47 change_request = EmailChange(member=self.member, email="new@example.org")
49 with mock.patch("members.services.process_email_change") as proc:
50 services.verify_email_change(change_request)
51 self.assertTrue(change_request.verified)
52 proc.assert_called_once_with(change_request)
54 def test_confirm_email_change(self):
55 change_request = EmailChange(member=self.member, email="new@example.org")
57 with mock.patch("members.services.process_email_change") as proc:
58 services.confirm_email_change(change_request)
59 self.assertTrue(change_request.confirmed)
60 proc.assert_called_once_with(change_request)
62 @mock.patch("members.emails.send_email_change_completion_message")
63 def test_process_email_change(self, send_message_mock):
64 change_request = EmailChange(member=self.member, email="new@example.org")
66 original_email = self.member.email
68 with self.subTest("Uncompleted request"):
69 services.process_email_change(change_request)
71 self.assertEqual(self.member.email, original_email)
72 send_message_mock.assert_not_called()
74 with self.subTest("Completed request"):
75 change_request.verified = True
76 change_request.confirmed = True
78 services.process_email_change(change_request)
80 self.assertEqual(self.member.email, change_request.email)
81 send_message_mock.assert_called_once_with(change_request)
84@freeze_time("2018-12-2")
85@override_settings(SUSPEND_SIGNALS=True)
86class DataMinimisationTest(TestCase):
87 @classmethod
88 def setUpTestData(cls):
89 cls.m1 = Member.objects.create(
90 username="test1",
91 first_name="Test1",
92 last_name="Example",
93 email="test1@example.org",
94 )
95 Profile.objects.create(user=cls.m1, student_number="s1234567")
96 cls.s1 = Membership.objects.create(
97 user=cls.m1,
98 type=Membership.MEMBER,
99 since=timezone.now().replace(year=2017, month=9, day=1),
100 until=timezone.now().replace(year=2018, month=9, day=1),
101 )
102 cls.m2 = Member.objects.create(
103 username="test2",
104 first_name="Test2",
105 last_name="Example",
106 email="test2@example.org",
107 )
108 Profile.objects.create(user=cls.m2, student_number="s7654321")
109 cls.s2 = Membership.objects.create(
110 user=cls.m2,
111 type=Membership.MEMBER,
112 since=timezone.now().replace(year=2017, month=9, day=1),
113 until=timezone.now().replace(year=2018, month=9, day=1),
114 )
116 def test_removes_after_31_days_or_no_membership(self):
117 with self.subTest("Deletes after 90 days"):
118 processed = services.execute_data_minimisation(True)
119 self.assertEqual(len(processed), 2)
120 self.assertEqual(processed[0], self.m1)
122 with self.subTest("Deletes after 90 days"):
123 self.s1.until = timezone.now().replace(year=2018, month=11, day=1)
124 self.s1.save()
125 processed = services.execute_data_minimisation(True)
126 self.assertEqual(len(processed), 1)
128 with self.subTest("Deletes when no memberships"):
129 self.s1.delete()
130 processed = services.execute_data_minimisation(True)
131 self.assertEqual(len(processed), 2)
133 def test_provided_queryset(self):
134 processed = services.execute_data_minimisation(True, members=Member.objects)
135 self.assertEqual(len(processed), 2)
136 self.assertEqual(processed[0], self.m1)
138 def test_does_not_affect_current_members(self):
139 with self.subTest("Membership ends in future"):
140 self.s1.until = timezone.now().replace(year=2019, month=9, day=1)
141 self.s1.save()
142 processed = services.execute_data_minimisation(True)
143 self.assertEqual(len(processed), 1)
144 with self.subTest("Never ending membership"):
145 self.s1.until = None
146 self.s1.save()
147 processed = services.execute_data_minimisation(True)
148 self.assertEqual(len(processed), 1)
149 self.s1.until = timezone.now().replace(year=2018, month=9, day=1)
150 self.s1.save()
151 with self.subTest("Newer year membership after expired one"):
152 m = Membership.objects.create(
153 user=self.m1,
154 type=Membership.MEMBER,
155 since=timezone.now().replace(year=2018, month=9, day=10),
156 until=timezone.now().replace(year=2019, month=8, day=31),
157 )
158 processed = services.execute_data_minimisation(True)
159 self.assertEqual(len(processed), 1)
160 m.delete()
161 with self.subTest("Newer study membership after expired one"):
162 m = Membership.objects.create(
163 user=self.m1,
164 type=Membership.MEMBER,
165 since=timezone.now().replace(year=2018, month=9, day=10),
166 until=None,
167 )
168 processed = services.execute_data_minimisation(True)
169 self.assertEqual(len(processed), 1)
170 m.delete()