|
1 | 1 | import datetime
|
2 |
| -from unittest.mock import patch |
| 2 | +from unittest.mock import call, patch |
3 | 3 |
|
4 | 4 | import pytest
|
5 | 5 | from django.utils import timezone
|
| 6 | +from google.auth.exceptions import RefreshError |
6 | 7 | from googleapiclient.errors import HttpError
|
7 | 8 |
|
8 | 9 | from apps.google import constants, tasks
|
| 10 | +from apps.google.models import GoogleOAuth2User |
9 | 11 | from apps.schedules.models import CustomOnCallShift, OnCallScheduleWeb, ShiftSwapRequest
|
10 | 12 |
|
11 | 13 |
|
@@ -148,19 +150,61 @@ def __init__(self, reason=None, status=200) -> None:
|
148 | 150 |
|
149 | 151 |
|
150 | 152 | @patch("apps.google.client.build")
|
| 153 | +@pytest.mark.parametrize( |
| 154 | + "ErrorClass,http_status,should_reset_user_google_oauth2_settings,task_should_raise_exception", |
| 155 | + [ |
| 156 | + (RefreshError, None, True, False), |
| 157 | + (HttpError, 401, False, False), |
| 158 | + (HttpError, 500, False, False), |
| 159 | + (HttpError, 403, False, False), |
| 160 | + (Exception, None, False, True), |
| 161 | + ], |
| 162 | +) |
151 | 163 | @pytest.mark.django_db
|
152 |
| -def test_sync_out_of_office_calendar_events_for_user_httperror(mock_google_api_client_build, test_setup): |
153 |
| - mock_response = MockResponse(reason="forbidden", status=403) |
154 |
| - mock_google_api_client_build.return_value.events.return_value.list.return_value.execute.side_effect = HttpError( |
155 |
| - resp=mock_response, content=b"error" |
156 |
| - ) |
| 164 | +def test_sync_out_of_office_calendar_events_for_user_error_scenarios( |
| 165 | + mock_google_api_client_build, |
| 166 | + ErrorClass, |
| 167 | + http_status, |
| 168 | + should_reset_user_google_oauth2_settings, |
| 169 | + task_should_raise_exception, |
| 170 | + test_setup, |
| 171 | +): |
| 172 | + if ErrorClass == HttpError: |
| 173 | + mock_response = MockResponse(reason="forbidden", status=http_status) |
| 174 | + exception = ErrorClass(resp=mock_response, content=b"error") |
| 175 | + elif ErrorClass == RefreshError: |
| 176 | + exception = ErrorClass( |
| 177 | + "invalid_grant: Token has been expired or revoked.", |
| 178 | + {"error": "invalid_grant", "error_description": "Token has been expired or revoked."}, |
| 179 | + ) |
| 180 | + else: |
| 181 | + exception = ErrorClass() |
| 182 | + |
| 183 | + mock_google_api_client_build.return_value.events.return_value.list.return_value.execute.side_effect = exception |
157 | 184 |
|
158 | 185 | google_oauth2_user, schedule = test_setup([])
|
159 | 186 | user = google_oauth2_user.user
|
160 | 187 |
|
161 |
| - tasks.sync_out_of_office_calendar_events_for_user(google_oauth2_user.pk) |
| 188 | + assert user.google_calendar_settings is not None |
162 | 189 |
|
163 |
| - assert ShiftSwapRequest.objects.filter(beneficiary=user, schedule=schedule).count() == 0 |
| 190 | + if task_should_raise_exception: |
| 191 | + with pytest.raises(ErrorClass): |
| 192 | + tasks.sync_out_of_office_calendar_events_for_user(google_oauth2_user.pk) |
| 193 | + else: |
| 194 | + tasks.sync_out_of_office_calendar_events_for_user(google_oauth2_user.pk) |
| 195 | + |
| 196 | + assert ShiftSwapRequest.objects.filter(beneficiary=user, schedule=schedule).count() == 0 |
| 197 | + |
| 198 | + user.refresh_from_db() |
| 199 | + |
| 200 | + google_oauth2_user_count = GoogleOAuth2User.objects.filter(user=user).count() |
| 201 | + |
| 202 | + if should_reset_user_google_oauth2_settings: |
| 203 | + assert user.google_calendar_settings is None |
| 204 | + assert google_oauth2_user_count == 0 |
| 205 | + else: |
| 206 | + assert user.google_calendar_settings is not None |
| 207 | + assert google_oauth2_user_count == 1 |
164 | 208 |
|
165 | 209 |
|
166 | 210 | @patch("apps.google.client.build")
|
@@ -374,14 +418,50 @@ def _fetch_shift_swap_requests():
|
374 | 418 | assert _fetch_shift_swap_requests().count() == 1
|
375 | 419 |
|
376 | 420 |
|
| 421 | +REQUIRED_SCOPE_1 = "https://www.googleapis.com/test/foo" |
| 422 | +REQUIRED_SCOPE_2 = "https://www.googleapis.com/test/bar" |
| 423 | + |
| 424 | + |
| 425 | +@patch("apps.google.tasks.constants.REQUIRED_OAUTH_SCOPES", [REQUIRED_SCOPE_1, REQUIRED_SCOPE_2]) |
| 426 | +@patch("apps.google.tasks.sync_out_of_office_calendar_events_for_user.apply_async") |
| 427 | +@pytest.mark.django_db |
| 428 | +def test_sync_out_of_office_calendar_events_for_all_users_only_called_for_tokens_having_all_required_scopes( |
| 429 | + mock_sync_out_of_office_calendar_events_for_user, |
| 430 | + make_organization_and_user, |
| 431 | + make_user_for_organization, |
| 432 | + make_google_oauth2_user_for_user, |
| 433 | +): |
| 434 | + organization, user1 = make_organization_and_user() |
| 435 | + user2 = make_user_for_organization(organization) |
| 436 | + user3 = make_user_for_organization(organization) |
| 437 | + |
| 438 | + missing_a_scope = f"{REQUIRED_SCOPE_1} foo_bar" |
| 439 | + has_all_scopes = f"{REQUIRED_SCOPE_1} {REQUIRED_SCOPE_2} foo_bar" |
| 440 | + |
| 441 | + _ = make_google_oauth2_user_for_user(user1, oauth_scope=missing_a_scope) |
| 442 | + user2_google_oauth2_user = make_google_oauth2_user_for_user(user2, oauth_scope=has_all_scopes) |
| 443 | + user3_google_oauth2_user = make_google_oauth2_user_for_user(user3, oauth_scope=has_all_scopes) |
| 444 | + |
| 445 | + tasks.sync_out_of_office_calendar_events_for_all_users() |
| 446 | + |
| 447 | + assert len(mock_sync_out_of_office_calendar_events_for_user.mock_calls) == 2 |
| 448 | + mock_sync_out_of_office_calendar_events_for_user.assert_has_calls( |
| 449 | + [ |
| 450 | + call(args=(user2_google_oauth2_user.pk,)), |
| 451 | + call(args=(user3_google_oauth2_user.pk,)), |
| 452 | + ], |
| 453 | + any_order=True, |
| 454 | + ) |
| 455 | + |
| 456 | + |
377 | 457 | @patch("apps.google.tasks.sync_out_of_office_calendar_events_for_user.apply_async")
|
378 | 458 | @pytest.mark.django_db
|
379 |
| -def test_sync_out_of_office_calendar_events_for_all_users( |
| 459 | +def test_sync_out_of_office_calendar_events_for_all_users_filters_out_users_from_deleted_organizations( |
380 | 460 | mock_sync_out_of_office_calendar_events_for_user,
|
381 | 461 | make_organization_and_user,
|
382 | 462 | make_google_oauth2_user_for_user,
|
383 | 463 | ):
|
384 |
| - organization, user = make_organization_and_user() |
| 464 | + _, user = make_organization_and_user() |
385 | 465 | google_oauth2_user = make_google_oauth2_user_for_user(user)
|
386 | 466 |
|
387 | 467 | deleted_organization, deleted_user = make_organization_and_user()
|
|
0 commit comments