Coverage for test/test_annosaurus.py: 96%
186 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-23 02:22 +0000
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-23 02:22 +0000
2import pytest
3import json
5from unittest.mock import patch
7from application.vars.annosaurus import Annosaurus, AuthenticationError
8from test.data.vars_responses import ex_23060001
11class MockResponse:
12 def __init__(self, url: str, method: str, status_code: int, headers=None, data=None):
13 self.url = url
14 self.status_code = status_code
15 self.method = method
16 self.headers = headers or {}
17 self.data = data
19 def json(self):
20 if self.status_code == 404:
21 return {}
22 if self.method == 'GET':
23 match self.url:
24 case 'http://localhost:test/observations/0059f860-4799-485f-c06c-5830e5ddd31e':
25 return ex_23060001['annotations'][0]
26 case 'http://localhost:test/observations/0d9133d7-1d49-47d5-4b6d-6e4fb25dd41e':
27 return ex_23060001['annotations'][1]
28 case 'http://localhost:test/observations/080118db-baa2-468a-d06a-144249c1d41e':
29 return ex_23060001['annotations'][2]
30 case 'http://localhost:test/observations/35aa2bb9-d067-419b-9a6e-09cdce8ed41e':
31 return ex_23060001['annotations'][3]
32 case 'http://localhost:test/observations/invalid':
33 return {}
34 elif self.method == 'POST':
35 match self.url:
36 case 'http://localhost:test/auth':
37 if self.headers.get('Authorization') == 'APIKEY valid':
38 return {'access_token': 'jwt'}
39 case 'http://localhost:test/associations':
40 data = self.data
41 del data['observation_uuid']
42 data['uuid'] = 'new_uuid'
43 return data
44 elif self.method == 'PUT':
45 match self.url:
46 case 'http://localhost:test/annotations/0059f860-4799-485f-c06c-5830e5ddd31e':
47 annotation = ex_23060001['annotations'][0].copy()
48 annotation['concept'] = self.data['concept']
49 return annotation
50 case 'http://localhost:test/associations/abc123':
51 data = self.data
52 data['uuid'] = 'abc123'
53 return self.data
54 case 'http://localhost:test/associations/c4eaa100-comment':
55 data = self.data
56 data['uuid'] = 'c4eaa100-comment'
57 return self.data
58 case 'http://localhost:test/associations/faf820ac-93fd-4d5a-486a-87775ec1d41e':
59 data = self.data
60 data['uuid'] = 'faf820ac-93fd-4d5a-486a-87775ec1d41e'
61 return self.data
62 case 'http://localhost:test/associations/297d23d7-5979-46e7-6f66-8f1fcf8ed41e':
63 data = self.data
64 data['uuid'] = '297d23d7-5979-46e7-6f66-8f1fcf8ed41e'
65 return self.data
66 elif self.method == 'DELETE':
67 match self.url:
68 case 'http://localhost:test/associations/abc123':
69 return {}
70 raise json.JSONDecodeError('Unable to decode JSON', '', 0)
72 def text(self):
73 return '<html>Invalid</html>'
76def mocked_requests_get(*args, **kwargs):
77 return MockResponse(
78 url=kwargs.get('url'),
79 method='GET',
80 status_code=200,
81 headers=kwargs.get('headers'),
82 )
85def mocked_requests_get_404(*args, **kwargs):
86 return MockResponse(
87 url=kwargs.get('url'),
88 method='GET',
89 status_code=404,
90 headers=kwargs.get('headers'),
91 )
94def mocked_requests_post(*args, **kwargs):
95 return MockResponse(
96 url=kwargs.get('url'),
97 method='POST',
98 status_code=201,
99 headers=kwargs.get('headers'),
100 data=kwargs.get('data'),
101 )
104def mocked_requests_put(*args, **kwargs):
105 return MockResponse(
106 url=kwargs.get('url'),
107 method='PUT',
108 status_code=200,
109 headers=kwargs.get('headers'),
110 data=kwargs.get('data'),
111 )
114def mocked_requests_delete(*args, **kwargs):
115 return MockResponse(
116 url=kwargs.get('url'),
117 method='DELETE',
118 status_code=204,
119 headers=kwargs.get('headers'),
120 )
123class TestAnnosaurus:
124 def test_init(self):
125 anno = Annosaurus('http://localhost:test/')
126 assert anno.base_url == 'http://localhost:test'
128 def test_authorize_jwt(self):
129 anno = Annosaurus('http://localhost:test/')
130 assert anno.authorize(jwt='jwt') == 'jwt'
132 @patch('requests.post', side_effect=mocked_requests_post)
133 def test_authorize_client_secret(self, mock_post):
134 anno = Annosaurus('http://localhost:test/')
135 assert anno.authorize(client_secret='valid') == 'jwt'
136 assert mock_post.call_args[1]['headers'] == {'Authorization': 'APIKEY valid'}
138 @patch('requests.post', side_effect=mocked_requests_post)
139 def test_authorize_invalid(self, _):
140 anno = Annosaurus('http://localhost:test/')
141 with pytest.raises(AuthenticationError):
142 anno.authorize(client_secret='invalid')
144 def test_authorize_none(self):
145 anno = Annosaurus('http://localhost:test/')
146 with pytest.raises(AuthenticationError):
147 anno.authorize()
149 def test_auth_header(self):
150 anno = Annosaurus('http://localhost:test/')
151 assert anno._auth_header('jwt') == {'Authorization': 'Bearer jwt'}
153 @patch('requests.post', side_effect=mocked_requests_post)
154 def test_create_association(self, _):
155 anno = Annosaurus('http://localhost:test')
156 new_association = {'link_name': 'test', 'to_concept': 'test'}
157 created = anno.create_association(
158 observation_uuid='abc123',
159 association=new_association,
160 jwt='jwt',
161 )
162 assert created['status'] == 201
163 assert created['json'] == {
164 'link_name': 'test',
165 'link_value': 'nil',
166 'to_concept': 'test',
167 'uuid': 'new_uuid',
168 }
170 def test_create_association_missing_link_value(self):
171 anno = Annosaurus('http://localhost:test')
172 with pytest.raises(ValueError):
173 anno.create_association(
174 observation_uuid='abc123',
175 association={'to_concept': 'test'},
176 jwt='jwt',
177 )
179 @patch('requests.put', side_effect=mocked_requests_put)
180 def test_update_association(self, _):
181 anno = Annosaurus('http://localhost:test')
182 updated = anno.update_association(
183 association_uuid='abc123',
184 association={'link_name': 'test', 'to_concept': 'test'},
185 jwt='jwt',
186 )
187 assert updated['status'] == 200
188 assert updated['json'] == {
189 'link_name': 'test',
190 'to_concept': 'test',
191 'uuid': 'abc123',
192 }
194 @patch('requests.delete', side_effect=mocked_requests_delete)
195 def test_delete_association(self, _):
196 anno = Annosaurus('http://localhost:test')
197 deleted = anno.delete_association(
198 association_uuid='abc123',
199 jwt='jwt',
200 )
201 assert deleted['status'] == 204
202 assert deleted['json'] == {}
204 @patch('requests.put', side_effect=mocked_requests_put)
205 def test_update_concept_name(self, _):
206 anno = Annosaurus('http://localhost:test')
207 updated = anno.update_concept_name(
208 observation_uuid='0059f860-4799-485f-c06c-5830e5ddd31e',
209 concept='Magikarp',
210 jwt='jwt',
211 )
212 old_anno = ex_23060001['annotations'][0].copy()
213 old_anno['concept'] = 'Magikarp'
214 assert updated['status'] == 200
215 assert updated['json'] == old_anno
217 @patch('requests.get', side_effect=mocked_requests_get_404)
218 def test_update_annotation_comment_404(self, _):
219 anno = Annosaurus('http://localhost:test')
220 updated = anno.update_annotation_comment(
221 observation_uuid='invalid',
222 reviewers=['Test Reviewer'],
223 jwt='jwt',
224 )
225 assert updated['status'] == 404
226 assert updated['json'] == {}
228 @patch('requests.get', side_effect=mocked_requests_get)
229 @patch('requests.post', side_effect=mocked_requests_post)
230 def test_update_annotation_comment_new_one_reviewer(self, _, __):
231 anno = Annosaurus('http://localhost:test')
232 created = anno.update_annotation_comment(
233 observation_uuid='0059f860-4799-485f-c06c-5830e5ddd31e',
234 reviewers=['Test Reviewer'],
235 jwt='jwt',
236 )
237 assert created['status'] == 201
238 assert created['json'] == {
239 'link_name': 'comment',
240 'link_value': 'Added for review: Test Reviewer',
241 'to_concept': 'self',
242 'uuid': 'new_uuid'
243 }
245 @patch('requests.get', side_effect=mocked_requests_get)
246 @patch('requests.post', side_effect=mocked_requests_post)
247 def test_update_annotation_comment_new_multiple_reviewers(self, _, __):
248 anno = Annosaurus('http://localhost:test')
249 created = anno.update_annotation_comment(
250 observation_uuid='0059f860-4799-485f-c06c-5830e5ddd31e',
251 reviewers=['Test Reviewer', 'Ronald McDonald'],
252 jwt='jwt',
253 )
254 assert created['status'] == 201
255 assert created['json'] == {
256 'link_name': 'comment',
257 'link_value': 'Added for review: Test Reviewer, Ronald McDonald',
258 'to_concept': 'self',
259 'uuid': 'new_uuid'
260 }
262 @patch('requests.get', side_effect=mocked_requests_get)
263 @patch('requests.put', side_effect=mocked_requests_put)
264 def test_update_annotation_comment_update_no_prev_reviewers(self, _, __):
265 anno = Annosaurus('http://localhost:test')
266 updated = anno.update_annotation_comment(
267 observation_uuid='0d9133d7-1d49-47d5-4b6d-6e4fb25dd41e',
268 reviewers=['J. Dolan'],
269 jwt='jwt',
270 )
271 assert updated['status'] == 200
272 assert updated['json'] == {
273 'link_value': 'this is a comment; Added for review: J. Dolan',
274 'uuid': 'c4eaa100-comment'
275 }
277 @patch('requests.get', side_effect=mocked_requests_get)
278 @patch('requests.put', side_effect=mocked_requests_put)
279 def test_update_annotation_comment_update_prev_reviewers_add(self, _, __):
280 anno = Annosaurus('http://localhost:test')
281 updated = anno.update_annotation_comment(
282 observation_uuid='080118db-baa2-468a-d06a-144249c1d41e',
283 reviewers=['J. Dolan', 'Don Draper'],
284 jwt='jwt',
285 )
286 assert updated['status'] == 200
287 assert updated['json'] == {
288 'link_value': 'Added for review: J. Dolan, Don Draper',
289 'uuid': 'faf820ac-93fd-4d5a-486a-87775ec1d41e'
290 }
292 @patch('requests.get', side_effect=mocked_requests_get)
293 @patch('requests.put', side_effect=mocked_requests_put)
294 def test_update_annotation_comment_update_prev_reviewers_replace(self, _, __):
295 anno = Annosaurus('http://localhost:test')
296 updated = anno.update_annotation_comment(
297 observation_uuid='080118db-baa2-468a-d06a-144249c1d41e',
298 reviewers=['J. Dolan'],
299 jwt='jwt',
300 )
301 assert updated['status'] == 200
302 assert updated['json'] == {
303 'link_value': 'Added for review: J. Dolan',
304 'uuid': 'faf820ac-93fd-4d5a-486a-87775ec1d41e'
305 }
307 @patch('requests.get', side_effect=mocked_requests_get)
308 @patch('requests.delete', side_effect=mocked_requests_delete)
309 def test_update_annotation_comment_delete_empty(self, _, __):
310 anno = Annosaurus('http://localhost:test')
311 deleted = anno.update_annotation_comment(
312 observation_uuid='080118db-baa2-468a-d06a-144249c1d41e',
313 reviewers=[],
314 jwt='jwt',
315 )
316 assert deleted['status'] == 204
317 assert deleted['json'] == {}
319 @patch('requests.get', side_effect=mocked_requests_get)
320 @patch('requests.put', side_effect=mocked_requests_put)
321 def test_update_annotation_comment_delete_not_empty(self, _, __):
322 anno = Annosaurus('http://localhost:test')
323 deleted = anno.update_annotation_comment(
324 observation_uuid='35aa2bb9-d067-419b-9a6e-09cdce8ed41e',
325 reviewers=[],
326 jwt='jwt',
327 )
328 assert deleted['status'] == 200
329 assert deleted['json'] == {
330 'link_value': 'This is a weird lookin sponge thing!',
331 'uuid': '297d23d7-5979-46e7-6f66-8f1fcf8ed41e'
332 }