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

1from datetime import date 

2from unittest import mock 

3 

4from django.test import TestCase, override_settings 

5from django.utils import timezone 

6 

7from freezegun import freeze_time 

8 

9from members import services 

10from members.models import EmailChange, Member, Membership, Profile 

11from members.services import gen_stats_year 

12 

13 

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) 

20 

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 ) 

26 

27 def test_gen_stats_year(self): 

28 result = gen_stats_year() 

29 

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]) 

32 

33 

34@override_settings(SUSPEND_SIGNALS=True) 

35class EmailChangeTest(TestCase): 

36 fixtures = ["members.json"] 

37 

38 @classmethod 

39 def setUpTestData(cls): 

40 # Add 10 members with default membership 

41 cls.member = Member.objects.get(pk=2) 

42 

43 def setUp(self): 

44 self.member.refresh_from_db() 

45 

46 def test_verify_email_change(self): 

47 change_request = EmailChange(member=self.member, email="new@example.org") 

48 

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) 

53 

54 def test_confirm_email_change(self): 

55 change_request = EmailChange(member=self.member, email="new@example.org") 

56 

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) 

61 

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") 

65 

66 original_email = self.member.email 

67 

68 with self.subTest("Uncompleted request"): 

69 services.process_email_change(change_request) 

70 

71 self.assertEqual(self.member.email, original_email) 

72 send_message_mock.assert_not_called() 

73 

74 with self.subTest("Completed request"): 

75 change_request.verified = True 

76 change_request.confirmed = True 

77 

78 services.process_email_change(change_request) 

79 

80 self.assertEqual(self.member.email, change_request.email) 

81 send_message_mock.assert_called_once_with(change_request) 

82 

83 

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 ) 

115 

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) 

121 

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) 

127 

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) 

132 

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) 

137 

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()