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
« 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
4===============================================================================
6 Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
7 Created by Rudolf Cardinal (rnc1001@cam.ac.uk).
9 This file is part of CamCOPS.
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.
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.
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/>.
24===============================================================================
26"""
28from urllib.parse import parse_qs, urlsplit
30from cardinal_pythonlib.uriconst import UriSchemes
31from pendulum import Duration
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
51# =============================================================================
52# Unit tests
53# =============================================================================
56class TaskScheduleTests(DemoRequestTestCase):
57 def test_deleting_deletes_related_objects(self) -> None:
58 patient = ServerCreatedPatientFactory()
59 schedule = TaskScheduleFactory(group=patient._group)
61 item = TaskScheduleItemFactory(
62 task_schedule=schedule,
63 task_table_name="ace3",
64 )
66 pts = PatientTaskScheduleFactory(
67 task_schedule=schedule,
68 patient=patient,
69 )
71 pts_email = PatientTaskScheduleEmailFactory(
72 patient_task_schedule=pts,
73 )
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 )
98 self.dbsession.delete(schedule)
99 self.dbsession.commit()
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 )
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")
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")
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)
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)
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)
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)
158 self.assertIn(
159 f"{pts.patient.uuid_as_proquint}", pts.email_body(self.req)
160 )
162 def test_email_body_contains_server_url(self) -> None:
163 schedule = TaskScheduleFactory(email_template="{server_url}")
164 pts = PatientTaskScheduleFactory(task_schedule=schedule)
166 expected_url = self.req.route_url(Routes.CLIENT_API)
168 self.assertIn(f"{expected_url}", pts.email_body(self.req))
170 def test_email_body_contains_patient_forename(self) -> None:
171 schedule = TaskScheduleFactory(email_template="{forename}")
172 pts = PatientTaskScheduleFactory(task_schedule=schedule)
174 self.assertIn(f"{pts.patient.forename}", pts.email_body(self.req))
176 def test_email_body_contains_patient_surname(self) -> None:
177 schedule = TaskScheduleFactory(email_template="{surname}")
178 pts = PatientTaskScheduleFactory(task_schedule=schedule)
180 self.assertIn(f"{pts.patient.surname}", pts.email_body(self.req))
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)
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 )
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)
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 )
220 def test_email_body_disallows_invalid_template(self) -> None:
221 schedule = TaskScheduleFactory(email_template="{foobar}")
222 pts = PatientTaskScheduleFactory(task_schedule=schedule)
224 with self.assertRaises(KeyError):
225 pts.email_body(self.req)
227 def test_email_body_disallows_accessing_properties(self) -> None:
228 schedule = TaskScheduleFactory(email_template="{server_url.__class__}")
229 pts = PatientTaskScheduleFactory(task_schedule=schedule)
231 with self.assertRaises(KeyError):
232 pts.email_body(self.req)
234 def test_email_sent_false_for_no_emails(self) -> None:
235 pts = PatientTaskScheduleFactory()
236 self.assertFalse(pts.email_sent)
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)
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)