Coverage for cc_modules/tests/cc_taskschedule_tests.py: 17%
172 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-08 23:14 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-08 23:14 +0000
1#!/usr/bin/env python
3"""
4camcops_server/cc_modules/tests/cc_taskschedule_tests.py
6===============================================================================
8 Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
9 Created by Rudolf Cardinal (rnc1001@cam.ac.uk).
11 This file is part of CamCOPS.
13 CamCOPS is free software: you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
18 CamCOPS is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
26===============================================================================
28"""
30from urllib.parse import parse_qs, urlsplit
32from cardinal_pythonlib.uriconst import UriSchemes
33from pendulum import Duration
35from camcops_server.cc_modules.cc_email import Email
36from camcops_server.cc_modules.cc_pyramid import Routes
37from camcops_server.cc_modules.cc_taskschedule import (
38 PatientTaskSchedule,
39 PatientTaskScheduleEmail,
40 TaskSchedule,
41 TaskScheduleItem,
42)
43from camcops_server.cc_modules.cc_unittest import (
44 DemoDatabaseTestCase,
45 DemoRequestTestCase,
46)
49# =============================================================================
50# Unit tests
51# =============================================================================
54class TaskScheduleTests(DemoDatabaseTestCase):
55 def test_deleting_deletes_related_objects(self) -> None:
56 schedule = TaskSchedule()
57 schedule.group_id = self.group.id
58 self.dbsession.add(schedule)
59 self.dbsession.flush()
61 item = TaskScheduleItem()
62 item.schedule_id = schedule.id
63 item.task_table_name = "ace3"
64 item.due_from = Duration(days=30)
65 item.due_by = Duration(days=60)
66 self.dbsession.add(item)
67 self.dbsession.flush()
69 patient = self.create_patient()
71 pts = PatientTaskSchedule()
72 pts.schedule_id = schedule.id
73 pts.patient_pk = patient.pk
74 self.dbsession.add(pts)
75 self.dbsession.flush()
77 email = Email()
78 self.dbsession.add(email)
79 self.dbsession.flush()
81 pts_email = PatientTaskScheduleEmail()
82 pts_email.email_id = email.id
83 pts_email.patient_task_schedule_id = pts.id
84 self.dbsession.add(pts_email)
85 self.dbsession.commit()
87 self.assertIsNotNone(
88 self.dbsession.query(TaskScheduleItem)
89 .filter(TaskScheduleItem.id == item.id)
90 .one_or_none()
91 )
92 self.assertIsNotNone(
93 self.dbsession.query(PatientTaskSchedule)
94 .filter(PatientTaskSchedule.id == pts.id)
95 .one_or_none()
96 )
97 self.assertIsNotNone(
98 self.dbsession.query(PatientTaskScheduleEmail)
99 .filter(
100 PatientTaskScheduleEmail.patient_task_schedule_id == pts.id
101 )
102 .one_or_none()
103 )
104 self.assertIsNotNone(
105 self.dbsession.query(Email)
106 .filter(Email.id == email.id)
107 .one_or_none()
108 )
110 self.dbsession.delete(schedule)
111 self.dbsession.commit()
113 self.assertIsNone(
114 self.dbsession.query(TaskScheduleItem)
115 .filter(TaskScheduleItem.id == item.id)
116 .one_or_none()
117 )
118 self.assertIsNone(
119 self.dbsession.query(PatientTaskSchedule)
120 .filter(PatientTaskSchedule.id == pts.id)
121 .one_or_none()
122 )
123 self.assertIsNone(
124 self.dbsession.query(PatientTaskScheduleEmail)
125 .filter(
126 PatientTaskScheduleEmail.patient_task_schedule_id == pts.id
127 )
128 .one_or_none()
129 )
130 self.assertIsNone(
131 self.dbsession.query(Email)
132 .filter(Email.id == email.id)
133 .one_or_none()
134 )
137class TaskScheduleItemTests(DemoRequestTestCase):
138 def test_description_shows_shortname_and_number_of_days(self) -> None:
139 item = TaskScheduleItem()
140 item.task_table_name = "bmi"
141 item.due_from = Duration(days=30)
143 self.assertEqual(item.description(self.req), "BMI @ 30 days")
145 def test_description_with_no_durations(self) -> None:
146 item = TaskScheduleItem()
147 item.task_table_name = "bmi"
149 self.assertEqual(item.description(self.req), "BMI @ ? days")
151 def test_due_within_calculated_from_due_by_and_due_from(self) -> None:
152 item = TaskScheduleItem()
153 item.due_from = Duration(days=30)
154 item.due_by = Duration(days=50)
156 self.assertEqual(item.due_within.in_days(), 20)
158 def test_due_within_is_none_when_missing_due_by(self) -> None:
159 item = TaskScheduleItem()
160 item.due_from = Duration(days=30)
162 self.assertIsNone(item.due_within)
164 def test_due_within_calculated_when_missing_due_from(self) -> None:
165 item = TaskScheduleItem()
166 item.due_by = Duration(days=30)
168 self.assertEqual(item.due_within.in_days(), 30)
171class PatientTaskScheduleTests(DemoDatabaseTestCase):
172 def setUp(self) -> None:
173 super().setUp()
175 import datetime
177 self.schedule = TaskSchedule()
178 self.schedule.group_id = self.group.id
179 self.dbsession.add(self.schedule)
181 self.patient = self.create_patient(
182 id=1,
183 forename="Jo",
184 surname="Patient",
185 dob=datetime.date(1958, 4, 19),
186 sex="F",
187 address="Address",
188 gp="GP",
189 other="Other",
190 )
192 self.pts = PatientTaskSchedule()
193 self.pts.schedule_id = self.schedule.id
194 self.pts.patient_pk = self.patient.pk
195 self.dbsession.add(self.pts)
196 self.dbsession.flush()
198 def test_email_body_contains_access_key(self) -> None:
199 self.schedule.email_template = "{access_key}"
200 self.dbsession.add(self.schedule)
201 self.dbsession.flush()
203 self.assertIn(
204 f"{self.patient.uuid_as_proquint}", self.pts.email_body(self.req)
205 )
207 def test_email_body_contains_server_url(self) -> None:
208 self.schedule.email_template = "{server_url}"
209 self.dbsession.add(self.schedule)
210 self.dbsession.flush()
212 expected_url = self.req.route_url(Routes.CLIENT_API)
214 self.assertIn(f"{expected_url}", self.pts.email_body(self.req))
216 def test_email_body_contains_patient_forename(self) -> None:
217 self.schedule.email_template = "{forename}"
218 self.dbsession.add(self.schedule)
219 self.dbsession.flush()
221 self.assertIn(
222 f"{self.pts.patient.forename}", self.pts.email_body(self.req)
223 )
225 def test_email_body_contains_patient_surname(self) -> None:
226 self.schedule.email_template = "{surname}"
227 self.dbsession.add(self.schedule)
228 self.dbsession.flush()
230 self.assertIn(
231 f"{self.pts.patient.surname}", self.pts.email_body(self.req)
232 )
234 def test_email_body_contains_android_launch_url(self) -> None:
235 self.schedule.email_template = "{android_launch_url}"
236 self.dbsession.add(self.schedule)
237 self.dbsession.flush()
239 url = self.pts.email_body(self.req)
240 (scheme, netloc, path, query, fragment) = urlsplit(url)
241 self.assertEqual(scheme, UriSchemes.HTTP)
242 self.assertEqual(netloc, "camcops.org")
243 self.assertEqual(path, "/register/")
244 query_dict = parse_qs(query)
245 self.assertEqual(query_dict["default_single_user_mode"], ["true"])
246 self.assertEqual(
247 query_dict["default_server_location"],
248 [self.req.route_url(Routes.CLIENT_API)],
249 )
250 self.assertEqual(
251 query_dict["default_access_key"], [self.patient.uuid_as_proquint]
252 )
254 def test_email_body_contains_ios_launch_url(self) -> None:
255 self.schedule.email_template = "{ios_launch_url}"
256 self.dbsession.add(self.schedule)
257 self.dbsession.flush()
259 url = self.pts.email_body(self.req)
260 (scheme, netloc, path, query, fragment) = urlsplit(url)
261 self.assertEqual(scheme, "camcops")
262 self.assertEqual(netloc, "camcops.org")
263 self.assertEqual(path, "/register/")
264 query_dict = parse_qs(query)
265 self.assertEqual(query_dict["default_single_user_mode"], ["true"])
266 self.assertEqual(
267 query_dict["default_server_location"],
268 [self.req.route_url(Routes.CLIENT_API)],
269 )
270 self.assertEqual(
271 query_dict["default_access_key"], [self.patient.uuid_as_proquint]
272 )
274 def test_email_body_disallows_invalid_template(self) -> None:
275 self.schedule.email_template = "{foobar}"
276 self.dbsession.add(self.schedule)
277 self.dbsession.flush()
279 with self.assertRaises(KeyError):
280 self.pts.email_body(self.req)
282 def test_email_body_disallows_accessing_properties(self) -> None:
283 self.schedule.email_template = "{server_url.__class__}"
284 self.dbsession.add(self.schedule)
285 self.dbsession.flush()
287 with self.assertRaises(KeyError):
288 self.pts.email_body(self.req)
290 def test_email_sent_false_for_no_emails(self) -> None:
291 self.assertFalse(self.pts.email_sent)
293 def test_email_sent_false_for_one_unsent_email(self) -> None:
294 email1 = Email()
295 email1.sent = False
296 self.dbsession.add(email1)
297 self.dbsession.flush()
298 pts_email1 = PatientTaskScheduleEmail()
299 pts_email1.email_id = email1.id
300 pts_email1.patient_task_schedule_id = self.pts.id
301 self.dbsession.add(pts_email1)
302 self.dbsession.commit()
304 self.assertFalse(self.pts.email_sent)
306 def test_email_sent_true_for_one_sent_email(self) -> None:
307 email1 = Email()
308 email1.sent = False
309 self.dbsession.add(email1)
310 self.dbsession.flush()
311 pts_email1 = PatientTaskScheduleEmail()
312 pts_email1.email_id = email1.id
313 pts_email1.patient_task_schedule_id = self.pts.id
314 self.dbsession.add(pts_email1)
316 email2 = Email()
317 email2.sent = True
318 self.dbsession.add(email2)
319 self.dbsession.flush()
320 pts_email2 = PatientTaskScheduleEmail()
321 pts_email2.email_id = email2.id
322 pts_email2.patient_task_schedule_id = self.pts.id
323 self.dbsession.add(pts_email2)
324 self.dbsession.commit()
326 self.assertTrue(self.pts.email_sent)