Coverage for cc_modules/tests/cc_taskschedule_tests.py: 27%

104 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2025-01-30 13:48 +0000

1""" 

2camcops_server/cc_modules/tests/cc_taskschedule_tests.py 

3 

4=============================================================================== 

5 

6 Copyright (C) 2012, University of Cambridge, Department of Psychiatry. 

7 Created by Rudolf Cardinal (rnc1001@cam.ac.uk). 

8 

9 This file is part of CamCOPS. 

10 

11 CamCOPS is free software: you can redistribute it and/or modify 

12 it under the terms of the GNU General Public License as published by 

13 the Free Software Foundation, either version 3 of the License, or 

14 (at your option) any later version. 

15 

16 CamCOPS is distributed in the hope that it will be useful, 

17 but WITHOUT ANY WARRANTY; without even the implied warranty of 

18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

19 GNU General Public License for more details. 

20 

21 You should have received a copy of the GNU General Public License 

22 along with CamCOPS. If not, see <https://www.gnu.org/licenses/>. 

23 

24=============================================================================== 

25 

26""" 

27 

28from urllib.parse import parse_qs, urlsplit 

29 

30from cardinal_pythonlib.uriconst import UriSchemes 

31from pendulum import Duration 

32 

33from camcops_server.cc_modules.cc_email import Email 

34from camcops_server.cc_modules.cc_pyramid import Routes 

35from camcops_server.cc_modules.cc_taskschedule import ( 

36 PatientTaskSchedule, 

37 PatientTaskScheduleEmail, 

38 TaskScheduleItem, 

39) 

40from camcops_server.cc_modules.cc_testfactories import ( 

41 EmailFactory, 

42 PatientTaskScheduleEmailFactory, 

43 PatientTaskScheduleFactory, 

44 ServerCreatedPatientFactory, 

45 TaskScheduleFactory, 

46 TaskScheduleItemFactory, 

47) 

48from camcops_server.cc_modules.cc_unittest import DemoRequestTestCase 

49 

50 

51# ============================================================================= 

52# Unit tests 

53# ============================================================================= 

54 

55 

56class TaskScheduleTests(DemoRequestTestCase): 

57 def test_deleting_deletes_related_objects(self) -> None: 

58 patient = ServerCreatedPatientFactory() 

59 schedule = TaskScheduleFactory(group=patient._group) 

60 

61 item = TaskScheduleItemFactory( 

62 task_schedule=schedule, 

63 task_table_name="ace3", 

64 ) 

65 

66 pts = PatientTaskScheduleFactory( 

67 task_schedule=schedule, 

68 patient=patient, 

69 ) 

70 

71 pts_email = PatientTaskScheduleEmailFactory( 

72 patient_task_schedule=pts, 

73 ) 

74 

75 self.assertIsNotNone( 

76 self.dbsession.query(TaskScheduleItem) 

77 .filter(TaskScheduleItem.id == item.id) 

78 .one_or_none() 

79 ) 

80 self.assertIsNotNone( 

81 self.dbsession.query(PatientTaskSchedule) 

82 .filter(PatientTaskSchedule.id == pts.id) 

83 .one_or_none() 

84 ) 

85 self.assertIsNotNone( 

86 self.dbsession.query(PatientTaskScheduleEmail) 

87 .filter( 

88 PatientTaskScheduleEmail.patient_task_schedule_id == pts.id 

89 ) 

90 .one_or_none() 

91 ) 

92 self.assertIsNotNone( 

93 self.dbsession.query(Email) 

94 .filter(Email.id == pts_email.email.id) 

95 .one_or_none() 

96 ) 

97 

98 self.dbsession.delete(schedule) 

99 self.dbsession.commit() 

100 

101 self.assertIsNone( 

102 self.dbsession.query(TaskScheduleItem) 

103 .filter(TaskScheduleItem.id == item.id) 

104 .one_or_none() 

105 ) 

106 self.assertIsNone( 

107 self.dbsession.query(PatientTaskSchedule) 

108 .filter(PatientTaskSchedule.id == pts.id) 

109 .one_or_none() 

110 ) 

111 self.assertIsNone( 

112 self.dbsession.query(PatientTaskScheduleEmail) 

113 .filter( 

114 PatientTaskScheduleEmail.patient_task_schedule_id == pts.id 

115 ) 

116 .one_or_none() 

117 ) 

118 self.assertIsNone( 

119 self.dbsession.query(Email) 

120 .filter(Email.id == pts_email.email.id) 

121 .one_or_none() 

122 ) 

123 

124 

125class TaskScheduleItemTests(DemoRequestTestCase): 

126 def test_description_shows_shortname_and_number_of_days(self) -> None: 

127 item = TaskScheduleItemFactory( 

128 task_table_name="bmi", 

129 due_from=Duration(days=30), 

130 ) 

131 self.assertEqual(item.description(self.req), "BMI @ 30 days") 

132 

133 def test_description_with_no_durations(self) -> None: 

134 item = TaskScheduleItemFactory(task_table_name="bmi") 

135 self.assertEqual(item.description(self.req), "BMI @ ? days") 

136 

137 def test_due_within_calculated_from_due_by_and_due_from(self) -> None: 

138 item = TaskScheduleItemFactory( 

139 due_from=Duration(days=30), 

140 due_by=Duration(days=50), 

141 ) 

142 self.assertEqual(item.due_within.in_days(), 20) 

143 

144 def test_due_within_is_none_when_missing_due_by(self) -> None: 

145 item = TaskScheduleItemFactory(due_from=Duration(days=30)) 

146 self.assertIsNone(item.due_within) 

147 

148 def test_due_within_calculated_when_missing_due_from(self) -> None: 

149 item = TaskScheduleItemFactory(due_by=Duration(days=30)) 

150 self.assertEqual(item.due_within.in_days(), 30) 

151 

152 

153class PatientTaskScheduleTests(DemoRequestTestCase): 

154 def test_email_body_contains_access_key(self) -> None: 

155 schedule = TaskScheduleFactory(email_template="{access_key}") 

156 pts = PatientTaskScheduleFactory(task_schedule=schedule) 

157 

158 self.assertIn( 

159 f"{pts.patient.uuid_as_proquint}", pts.email_body(self.req) 

160 ) 

161 

162 def test_email_body_contains_server_url(self) -> None: 

163 schedule = TaskScheduleFactory(email_template="{server_url}") 

164 pts = PatientTaskScheduleFactory(task_schedule=schedule) 

165 

166 expected_url = self.req.route_url(Routes.CLIENT_API) 

167 

168 self.assertIn(f"{expected_url}", pts.email_body(self.req)) 

169 

170 def test_email_body_contains_patient_forename(self) -> None: 

171 schedule = TaskScheduleFactory(email_template="{forename}") 

172 pts = PatientTaskScheduleFactory(task_schedule=schedule) 

173 

174 self.assertIn(f"{pts.patient.forename}", pts.email_body(self.req)) 

175 

176 def test_email_body_contains_patient_surname(self) -> None: 

177 schedule = TaskScheduleFactory(email_template="{surname}") 

178 pts = PatientTaskScheduleFactory(task_schedule=schedule) 

179 

180 self.assertIn(f"{pts.patient.surname}", pts.email_body(self.req)) 

181 

182 def test_email_body_contains_android_launch_url(self) -> None: 

183 schedule = TaskScheduleFactory(email_template="{android_launch_url}") 

184 pts = PatientTaskScheduleFactory(task_schedule=schedule) 

185 

186 url = pts.email_body(self.req) 

187 (scheme, netloc, path, query, fragment) = urlsplit(url) 

188 self.assertEqual(scheme, UriSchemes.HTTP) 

189 self.assertEqual(netloc, "camcops.org") 

190 self.assertEqual(path, "/register/") 

191 query_dict = parse_qs(query) 

192 self.assertEqual(query_dict["default_single_user_mode"], ["true"]) 

193 self.assertEqual( 

194 query_dict["default_server_location"], 

195 [self.req.route_url(Routes.CLIENT_API)], 

196 ) 

197 self.assertEqual( 

198 query_dict["default_access_key"], [pts.patient.uuid_as_proquint] 

199 ) 

200 

201 def test_email_body_contains_ios_launch_url(self) -> None: 

202 schedule = TaskScheduleFactory(email_template="{ios_launch_url}") 

203 pts = PatientTaskScheduleFactory(task_schedule=schedule) 

204 

205 url = pts.email_body(self.req) 

206 (scheme, netloc, path, query, fragment) = urlsplit(url) 

207 self.assertEqual(scheme, "camcops") 

208 self.assertEqual(netloc, "camcops.org") 

209 self.assertEqual(path, "/register/") 

210 query_dict = parse_qs(query) 

211 self.assertEqual(query_dict["default_single_user_mode"], ["true"]) 

212 self.assertEqual( 

213 query_dict["default_server_location"], 

214 [self.req.route_url(Routes.CLIENT_API)], 

215 ) 

216 self.assertEqual( 

217 query_dict["default_access_key"], [pts.patient.uuid_as_proquint] 

218 ) 

219 

220 def test_email_body_disallows_invalid_template(self) -> None: 

221 schedule = TaskScheduleFactory(email_template="{foobar}") 

222 pts = PatientTaskScheduleFactory(task_schedule=schedule) 

223 

224 with self.assertRaises(KeyError): 

225 pts.email_body(self.req) 

226 

227 def test_email_body_disallows_accessing_properties(self) -> None: 

228 schedule = TaskScheduleFactory(email_template="{server_url.__class__}") 

229 pts = PatientTaskScheduleFactory(task_schedule=schedule) 

230 

231 with self.assertRaises(KeyError): 

232 pts.email_body(self.req) 

233 

234 def test_email_sent_false_for_no_emails(self) -> None: 

235 pts = PatientTaskScheduleFactory() 

236 self.assertFalse(pts.email_sent) 

237 

238 def test_email_sent_false_for_one_unsent_email(self) -> None: 

239 email1 = EmailFactory(sent=False) 

240 pts_email1 = PatientTaskScheduleEmailFactory(email=email1) 

241 self.assertFalse(pts_email1.patient_task_schedule.email_sent) 

242 

243 def test_email_sent_true_for_one_sent_email(self) -> None: 

244 email1 = EmailFactory(sent=True) 

245 pts_email1 = PatientTaskScheduleEmailFactory(email=email1) 

246 self.assertTrue(pts_email1.patient_task_schedule.email_sent)