Skip to content

Commit 9cb8fa2

Browse files
committed
test: add HTTP status code tests for API services
Add comprehensive tests for 400, 404, and 410 status codes across API service functions: - fetch_place_as_json - fetch_event_as_json - update_event_to_linkedevents_api - resolve_unit_name_with_unit_id Organize tests into separate classes for better maintainability. Each test verifies correct exception handling (ApiBadRequestError for 400, ObjectDoesNotExistError for 404/410) with appropriate error messages distinguishing "not found" from "gone". Refs: PT-1989
1 parent 09e9a12 commit 9cb8fa2

1 file changed

Lines changed: 207 additions & 108 deletions

File tree

Lines changed: 207 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from datetime import timedelta
2-
from unittest.mock import patch
2+
from unittest.mock import Mock, patch
33

44
import pytest
55
from django.utils import timezone
@@ -8,122 +8,221 @@
88
from common.utils import format_linked_event_datetime
99
from occurrences.event_api_services import api_client as le_api_client
1010
from occurrences.event_api_services import (
11+
fetch_event_as_json,
12+
fetch_place_as_json,
1113
get_enrollable_event_time_range_from_occurrences,
1214
resolve_unit_name_with_unit_id,
1315
send_event_republish,
1416
send_event_unpublish,
17+
update_event_to_linkedevents_api,
1518
)
1619
from occurrences.factories import OccurrenceFactory, PalvelutarjotinEventFactory
1720
from palvelutarjotin.exceptions import ApiBadRequestError, ObjectDoesNotExistError
1821

1922

20-
@pytest.mark.django_db
21-
@patch("occurrences.event_api_services.update_event_to_linkedevents_api")
22-
def test_send_event_republish(
23-
mock_update_event_to_linkedevents_api,
24-
mock_get_event_data,
25-
mock_update_event_data,
26-
p_event,
27-
):
28-
OccurrenceFactory.create_batch(3, p_event=p_event, cancelled=False)
29-
30-
first_occurrence = p_event.occurrences.earliest("start_time")
31-
last_occurrence = p_event.occurrences.latest("end_time")
32-
event_start = first_occurrence.start_time
33-
event_end = last_occurrence.end_time
34-
35-
# Set a logic enrolment_start
36-
p_event.enrolment_start = first_occurrence.start_time
37-
p_event.save()
23+
class TestSendEventRepublish:
24+
@pytest.mark.django_db
25+
@patch("occurrences.event_api_services.update_event_to_linkedevents_api")
26+
def test_republish_with_occurrences(
27+
self,
28+
mock_update_event_to_linkedevents_api,
29+
mock_get_event_data,
30+
mock_update_event_data,
31+
p_event,
32+
):
33+
OccurrenceFactory.create_batch(3, p_event=p_event, cancelled=False)
34+
35+
first_occurrence = p_event.occurrences.earliest("start_time")
36+
last_occurrence = p_event.occurrences.latest("end_time")
37+
event_start = first_occurrence.start_time
38+
event_end = last_occurrence.end_time
39+
40+
p_event.enrolment_start = first_occurrence.start_time
41+
p_event.save()
42+
43+
enrolling_ends = last_occurrence.start_time - timedelta(
44+
days=p_event.enrolment_end_days
45+
)
46+
send_event_republish(p_event)
47+
48+
called_linked_event_id = mock_update_event_to_linkedevents_api.call_args[0][0]
49+
event_obj = mock_update_event_to_linkedevents_api.call_args[0][1]
50+
assert called_linked_event_id == p_event.linked_event_id
51+
assert event_obj["start_time"] == format_linked_event_datetime(event_start)
52+
assert event_obj["end_time"] == format_linked_event_datetime(event_end)
53+
assert event_obj["enrolment_start_time"] == format_linked_event_datetime(
54+
p_event.enrolment_start
55+
)
56+
assert event_obj["enrolment_end_time"] == format_linked_event_datetime(
57+
enrolling_ends
58+
)
59+
assert event_obj["enrolment_end_time"] is not None
60+
61+
62+
class TestSendEventUnpublish:
63+
@pytest.mark.django_db
64+
@patch("occurrences.event_api_services.update_event_to_linkedevents_api")
65+
def test_unpublish_sets_draft_status(
66+
self,
67+
mock_update_event_to_linkedevents_api,
68+
mock_get_event_data,
69+
mock_update_event_data,
70+
p_event,
71+
):
72+
send_event_unpublish(p_event)
73+
74+
called_linked_event_id = mock_update_event_to_linkedevents_api.call_args[0][0]
75+
event_obj = mock_update_event_to_linkedevents_api.call_args[0][1]
76+
assert called_linked_event_id == p_event.linked_event_id
77+
assert event_obj["publication_status"] == "draft"
78+
79+
80+
class TestGetEnrollableEventTimeRangeFromOccurrences:
81+
@pytest.mark.django_db
82+
def test_no_active_occurrences(self, mock_get_event_data):
83+
p_event = PalvelutarjotinEventFactory()
84+
assert p_event.occurrences.count() == 0
85+
assert get_enrollable_event_time_range_from_occurrences(p_event) == (None, None)
86+
OccurrenceFactory(p_event=p_event, cancelled=True)
87+
assert get_enrollable_event_time_range_from_occurrences(p_event) == (None, None)
88+
89+
@pytest.mark.django_db
90+
def test_without_enrolment_start(self, mock_get_event_data):
91+
p_event = PalvelutarjotinEventFactory(enrolment_start=None)
92+
OccurrenceFactory(p_event=p_event, cancelled=False)
93+
assert get_enrollable_event_time_range_from_occurrences(p_event) == (None, None)
94+
95+
@pytest.mark.django_db
96+
def test_with_active_occurrences(self, mock_get_event_data):
97+
p_event = PalvelutarjotinEventFactory(enrolment_start=timezone.now())
98+
OccurrenceFactory(p_event=p_event, cancelled=False)
99+
(start, _) = get_enrollable_event_time_range_from_occurrences(p_event)
100+
assert start == p_event.enrolment_start
101+
102+
103+
class TestFetchPlaceAsJson:
104+
@patch("occurrences.event_api_services.api_client")
105+
def test_400_raises_bad_request_error(self, mock_api_client):
106+
mock_response = Mock()
107+
mock_response.status_code = 400
108+
mock_api_client.retrieve.return_value = mock_response
109+
110+
with pytest.raises(ApiBadRequestError):
111+
fetch_place_as_json("place_123")
112+
113+
@patch("occurrences.event_api_services.api_client")
114+
def test_404_raises_not_found_error(self, mock_api_client):
115+
mock_response = Mock()
116+
mock_response.status_code = 404
117+
mock_api_client.retrieve.return_value = mock_response
118+
119+
with pytest.raises(ObjectDoesNotExistError):
120+
fetch_place_as_json("place_123")
121+
122+
@patch("occurrences.event_api_services.api_client")
123+
def test_410_raises_gone_error(self, mock_api_client):
124+
mock_response = Mock()
125+
mock_response.status_code = 410
126+
mock_api_client.retrieve.return_value = mock_response
127+
128+
with pytest.raises(ObjectDoesNotExistError, match="no longer available"):
129+
fetch_place_as_json("place_123")
130+
131+
132+
class TestFetchEventAsJson:
133+
@patch("occurrences.event_api_services.api_client")
134+
def test_400_raises_bad_request_error(self, mock_api_client):
135+
mock_response = Mock()
136+
mock_response.status_code = 400
137+
mock_api_client.retrieve.return_value = mock_response
138+
139+
with pytest.raises(ApiBadRequestError):
140+
fetch_event_as_json("event_123")
141+
142+
@patch("occurrences.event_api_services.api_client")
143+
def test_404_raises_not_found_error(self, mock_api_client):
144+
mock_response = Mock()
145+
mock_response.status_code = 404
146+
mock_api_client.retrieve.return_value = mock_response
147+
148+
with pytest.raises(ObjectDoesNotExistError):
149+
fetch_event_as_json("event_123")
150+
151+
@patch("occurrences.event_api_services.api_client")
152+
def test_410_raises_gone_error(self, mock_api_client):
153+
mock_response = Mock()
154+
mock_response.status_code = 410
155+
mock_api_client.retrieve.return_value = mock_response
156+
157+
with pytest.raises(ObjectDoesNotExistError, match="no longer available"):
158+
fetch_event_as_json("event_123")
159+
160+
161+
class TestUpdateEventToLinkedeventsApi:
162+
@patch("occurrences.event_api_services.api_client")
163+
def test_400_raises_bad_request_error(self, mock_api_client):
164+
mock_response = Mock()
165+
mock_response.status_code = 400
166+
mock_api_client.update.return_value = mock_response
167+
168+
with pytest.raises(ApiBadRequestError):
169+
update_event_to_linkedevents_api("event_123", {"name": "Test"})
170+
171+
@patch("occurrences.event_api_services.api_client")
172+
def test_404_raises_not_found_error(self, mock_api_client):
173+
mock_response = Mock()
174+
mock_response.status_code = 404
175+
mock_api_client.update.return_value = mock_response
176+
177+
with pytest.raises(ObjectDoesNotExistError):
178+
update_event_to_linkedevents_api("event_123", {"name": "Test"})
179+
180+
@patch("occurrences.event_api_services.api_client")
181+
def test_410_raises_gone_error(self, mock_api_client):
182+
mock_response = Mock()
183+
mock_response.status_code = 410
184+
mock_api_client.update.return_value = mock_response
185+
186+
with pytest.raises(ObjectDoesNotExistError, match="no longer available"):
187+
update_event_to_linkedevents_api("event_123", {"name": "Test"})
188+
189+
190+
class TestResolveUnitNameWithUnitId:
191+
@pytest.mark.django_db
192+
@patch("occurrences.event_api_services.update_event_to_linkedevents_api")
193+
def test_raises_valueerror_without_unit_id(
194+
self, mock_update_event_to_linkedevents_api, study_group
195+
):
196+
study_group.unit_id = None
197+
with pytest.raises(ValueError):
198+
resolve_unit_name_with_unit_id(study_group)
38199

39-
enrolling_ends = last_occurrence.start_time - timedelta(
40-
days=p_event.enrolment_end_days
41-
)
42-
send_event_republish(p_event)
43-
44-
called_linked_event_id = mock_update_event_to_linkedevents_api.call_args[0][0]
45-
event_obj = mock_update_event_to_linkedevents_api.call_args[0][1]
46-
assert called_linked_event_id == p_event.linked_event_id
47-
assert event_obj["start_time"] == format_linked_event_datetime(event_start)
48-
assert event_obj["end_time"] == format_linked_event_datetime(event_end)
49-
assert event_obj["enrolment_start_time"] == format_linked_event_datetime(
50-
p_event.enrolment_start
51-
)
52-
assert event_obj["enrolment_end_time"] == format_linked_event_datetime(
53-
enrolling_ends
200+
@pytest.mark.django_db
201+
@pytest.mark.parametrize(
202+
"status_code,error_cls",
203+
[(400, ApiBadRequestError), (404, ObjectDoesNotExistError)],
54204
)
55-
assert event_obj["enrolment_end_time"] is not None
56-
57-
58-
@pytest.mark.django_db
59-
@patch("occurrences.event_api_services.update_event_to_linkedevents_api")
60-
def test_send_event_unpublish(
61-
mock_update_event_to_linkedevents_api,
62-
mock_get_event_data,
63-
mock_update_event_data,
64-
p_event,
65-
):
66-
send_event_unpublish(p_event)
67-
68-
called_linked_event_id = mock_update_event_to_linkedevents_api.call_args[0][0]
69-
event_obj = mock_update_event_to_linkedevents_api.call_args[0][1]
70-
assert called_linked_event_id == p_event.linked_event_id
71-
assert event_obj["publication_status"] == "draft"
72-
73-
74-
@pytest.mark.django_db
75-
def test_get_enrollable_event_time_range_from_occurrences_with_no_active_occurrences(
76-
mock_get_event_data,
77-
):
78-
p_event = PalvelutarjotinEventFactory()
79-
assert p_event.occurrences.count() == 0
80-
assert get_enrollable_event_time_range_from_occurrences(p_event) == (None, None)
81-
OccurrenceFactory(p_event=p_event, cancelled=True)
82-
assert get_enrollable_event_time_range_from_occurrences(p_event) == (None, None)
83-
84-
85-
@pytest.mark.django_db
86-
def test_get_enrollable_event_time_range_from_occurrences_without_enrolment_start(
87-
mock_get_event_data,
88-
):
89-
p_event = PalvelutarjotinEventFactory(enrolment_start=None)
90-
OccurrenceFactory(p_event=p_event, cancelled=False)
91-
assert get_enrollable_event_time_range_from_occurrences(p_event) == (None, None)
92-
93-
94-
@pytest.mark.django_db
95-
def test_get_enrollable_event_time_range_from_occurrences_with_active_occurrences(
96-
mock_get_event_data,
97-
):
98-
p_event = PalvelutarjotinEventFactory(enrolment_start=timezone.now())
99-
OccurrenceFactory(p_event=p_event, cancelled=False)
100-
(start, _) = get_enrollable_event_time_range_from_occurrences(p_event)
101-
assert start == p_event.enrolment_start
102-
103-
104-
@pytest.mark.django_db
105-
@patch("occurrences.event_api_services.update_event_to_linkedevents_api")
106-
def test_resolve_unit_name_with_unit_id_raises_valueerror_without_unit_id(
107-
mock_update_event_to_linkedevents_api, study_group
108-
):
109-
study_group.unit_id = None
110-
with pytest.raises(ValueError):
111-
resolve_unit_name_with_unit_id(study_group)
112-
113-
114-
@pytest.mark.django_db
115-
@pytest.mark.parametrize(
116-
"status_code,error_cls", [(400, ApiBadRequestError), (404, ObjectDoesNotExistError)]
117-
)
118-
@patch("occurrences.event_api_services.update_event_to_linkedevents_api")
119-
def test_resolve_unit_name_with_unit_id_raises_error_from_server_faults(
120-
mock_update_event_to_linkedevents_api, status_code, error_cls, study_group
121-
):
122-
study_group.unit_id = "kultus:123"
123-
with patch.object(
124-
le_api_client,
125-
"retrieve",
126-
return_value=mocked_json_response(data=None, status_code=status_code),
205+
@patch("occurrences.event_api_services.update_event_to_linkedevents_api")
206+
def test_raises_error_from_server_faults(
207+
self, mock_update_event_to_linkedevents_api, status_code, error_cls, study_group
127208
):
128-
with pytest.raises(error_cls):
129-
resolve_unit_name_with_unit_id(study_group)
209+
study_group.unit_id = "kultus:123"
210+
with patch.object(
211+
le_api_client,
212+
"retrieve",
213+
return_value=mocked_json_response(data=None, status_code=status_code),
214+
):
215+
with pytest.raises(error_cls):
216+
resolve_unit_name_with_unit_id(study_group)
217+
218+
@patch("occurrences.event_api_services.api_client")
219+
def test_410_raises_gone_error(self, mock_api_client):
220+
mock_response = Mock()
221+
mock_response.status_code = 410
222+
mock_api_client.retrieve.return_value = mock_response
223+
224+
mock_study_group = Mock()
225+
mock_study_group.unit_id = "unit_123"
226+
227+
with pytest.raises(ObjectDoesNotExistError, match="no longer available"):
228+
resolve_unit_name_with_unit_id(mock_study_group)

0 commit comments

Comments
 (0)