From 85ceb5ccd35c5f19d03d32b9329d07ce66e73db3 Mon Sep 17 00:00:00 2001 From: VineetBala-AOT Date: Mon, 22 Jan 2024 14:03:54 -0800 Subject: [PATCH] Adding unit tests for error handling --- met-api/src/met_api/models/widget_map.py | 2 +- .../met_api/services/engagement_service.py | 3 +- met-api/tests/unit/api/test_cac_form.py | 44 +++- met-api/tests/unit/api/test_comment.py | 18 ++ met-api/tests/unit/api/test_contact.py | 73 ++++++- .../api/test_email_verification_service.py | 52 ++++- met-api/tests/unit/api/test_engagement.py | 63 +++++- .../unit/api/test_engagement_membership.py | 85 +++++++- .../unit/api/test_engagement_settings.py | 42 +++- .../tests/unit/api/test_engagement_slug.py | 36 ++- met-api/tests/unit/api/test_feedback.py | 72 +++++- met-api/tests/unit/api/test_report_setting.py | 43 +++- met-api/tests/unit/api/test_submission.py | 17 +- met-api/tests/unit/api/test_subscription.py | 119 +++++++++- met-api/tests/unit/api/test_survey.py | 148 +++++++++++-- met-api/tests/unit/api/test_tenant.py | 45 ++++ met-api/tests/unit/api/test_user.py | 77 ++++++- .../tests/unit/api/test_user_membership.py | 28 ++- met-api/tests/unit/api/test_widget.py | 57 +++++ .../tests/unit/api/test_widget_document.py | 44 +++- met-api/tests/unit/api/test_widget_event.py | 133 +++++++++++- met-api/tests/unit/api/test_widget_map.py | 75 +++++++ .../tests/unit/api/test_widget_subscribe.py | 205 +++++++++++++++++- .../tests/unit/api/test_widget_timeline.py | 29 +++ met-api/tests/unit/api/test_widget_video.py | 29 +++ met-api/tests/utilities/factory_scenarios.py | 3 +- 26 files changed, 1474 insertions(+), 68 deletions(-) create mode 100644 met-api/tests/unit/api/test_tenant.py diff --git a/met-api/src/met_api/models/widget_map.py b/met-api/src/met_api/models/widget_map.py index ea70ae00e..d384501c0 100644 --- a/met-api/src/met_api/models/widget_map.py +++ b/met-api/src/met_api/models/widget_map.py @@ -34,7 +34,7 @@ def get_map(cls, widget_id) -> list[WidgetMap]: @classmethod def update_map(cls, widget_id, map_data: dict) -> WidgetMap: """Update map.""" - query = WidgetMap.query.filter_by(WidgetMap.widget_id == widget_id) + query = WidgetMap.query.filter_by(widget_id=widget_id) widget_map: WidgetMap = query.first() if not widget_map: return map_data diff --git a/met-api/src/met_api/services/engagement_service.py b/met-api/src/met_api/services/engagement_service.py index 4392da86b..cb05061cf 100644 --- a/met-api/src/met_api/services/engagement_service.py +++ b/met-api/src/met_api/services/engagement_service.py @@ -56,7 +56,8 @@ def get_engagement(self, engagement_id) -> EngagementSchema: engagement = EngagementSchema().dump(engagement_model) engagement['banner_url'] = self.object_storage.get_url(engagement['banner_filename']) - return engagement + return engagement + return None def get_engagements_paginated( self, diff --git a/met-api/tests/unit/api/test_cac_form.py b/met-api/tests/unit/api/test_cac_form.py index 9af5f3c7c..b1aac1345 100644 --- a/met-api/tests/unit/api/test_cac_form.py +++ b/met-api/tests/unit/api/test_cac_form.py @@ -18,8 +18,11 @@ """ import json from http import HTTPStatus -from unittest.mock import MagicMock +from unittest.mock import MagicMock, patch +import pytest +from met_api.exceptions.business_exception import BusinessException +from met_api.services.cac_form_service import CACFormService from met_api.utils.enums import ContentType from tests.utilities.factory_scenarios import TestCACForm, TestJwtClaims, TestSubscribeInfo, TestWidgetInfo from tests.utilities.factory_utils import factory_auth_header, factory_engagement_model, factory_widget_model @@ -49,7 +52,12 @@ def create_cac_form_submission(client, jwt, engagement_id, widget_id, form_data, ) -def test_create_form_submission(client, jwt, session): # pylint:disable=unused-argument +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.BAD_REQUEST), + (ValueError('Test error'), HTTPStatus.BAD_REQUEST), +]) +def test_create_form_submission(client, jwt, session, side_effect, + expected_status): # pylint:disable=unused-argument """Assert that cac form submission can be POSTed.""" engagement = factory_engagement_model() TestWidgetInfo.widget_subscribe['engagement_id'] = engagement.id @@ -69,8 +77,31 @@ def test_create_form_submission(client, jwt, session): # pylint:disable=unused- response_data = json.loads(rv.data) assert response_data.get('engagement_id') == engagement.id - -def test_get_cac_form_spreadsheet(mocker, client, jwt, session, + with patch.object(CACFormService, 'create_form_submission', side_effect=side_effect): + rv = client.post( + f'/api/engagements/{engagement.id}/cacform/{widget.id}', + data=json.dumps(form_data), + headers=headers, + content_type=ContentType.JSON.value, + ) + assert rv.status_code == expected_status + + with patch.object(CACFormService, 'create_form_submission', + side_effect=BusinessException('Test error', status_code=HTTPStatus.BAD_REQUEST)): + rv = client.post( + f'/api/engagements/{engagement.id}/cacform/{widget.id}', + data=json.dumps(form_data), + headers=headers, + content_type=ContentType.JSON.value, + ) + assert rv.status_code == HTTPStatus.BAD_REQUEST + + +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_get_cac_form_spreadsheet(mocker, client, jwt, session, side_effect, expected_status, setup_admin_user_and_claims): # pylint:disable=unused-argument """Assert that cac form submissions sheet can be fetched.""" user, claims = setup_admin_user_and_claims @@ -118,3 +149,8 @@ def test_get_cac_form_spreadsheet(mocker, client, jwt, session, mock_post_generate_document.assert_called() mock_get_access_token.assert_called() mock_post_upload_template.assert_called() + + with patch.object(CACFormService, 'export_cac_form_submissions_to_spread_sheet', side_effect=side_effect): + rv = client.get(f'/api/engagements/{engagement.id}/cacform/sheet', + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status diff --git a/met-api/tests/unit/api/test_comment.py b/met-api/tests/unit/api/test_comment.py index 3c434a9be..114c9567d 100644 --- a/met-api/tests/unit/api/test_comment.py +++ b/met-api/tests/unit/api/test_comment.py @@ -24,6 +24,7 @@ from met_api.constants.membership_type import MembershipType from met_api.constants.staff_note_type import StaffNoteType +from met_api.services.comment_service import CommentService from met_api.utils import notification from met_api.utils.enums import ContentType from tests.utilities.factory_scenarios import TestJwtClaims @@ -47,6 +48,11 @@ def test_get_comments(client, jwt, session): # pylint:disable=unused-argument rv = client.get(f'/api/comments/survey/{survey.id}', headers=headers, content_type=ContentType.JSON.value) assert rv.status_code == 200 + with patch.object(CommentService, 'get_comments_paginated', side_effect=ValueError('Test error')): + rv = client.get(f'/api/comments/survey/{survey.id}', headers=headers, content_type=ContentType.JSON.value) + + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + def test_review_comment(client, jwt, session): # pylint:disable=unused-argument """Assert that a comment can be reviewed.""" @@ -215,6 +221,12 @@ def test_get_comments_spreadsheet_staff(mocker, client, jwt, session, mock_get_access_token.assert_called() mock_post_upload_template.assert_called() + with patch.object(CommentService, 'export_comments_to_spread_sheet_staff', + side_effect=ValueError('Test error')): + rv = client.get(f'/api/comments/survey/{survey.id}/sheet/staff', + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + def test_get_comments_spreadsheet_proponent(mocker, client, jwt, session, setup_admin_user_and_claims): # pylint:disable=unused-argument @@ -256,6 +268,12 @@ def test_get_comments_spreadsheet_proponent(mocker, client, jwt, session, mock_get_access_token.assert_called() mock_post_upload_template.assert_called() + with patch.object(CommentService, 'export_comments_to_spread_sheet_proponent', + side_effect=ValueError('Test error')): + rv = client.get(f'/api/comments/survey/{survey.id}/sheet/proponent', + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + def test_get_comments_spreadsheet_without_role(mocker, client, jwt, session): # pylint:disable=unused-argument """Assert that proponent comments sheet can be fetched.""" diff --git a/met-api/tests/unit/api/test_contact.py b/met-api/tests/unit/api/test_contact.py index 523148d4a..17b884f43 100644 --- a/met-api/tests/unit/api/test_contact.py +++ b/met-api/tests/unit/api/test_contact.py @@ -20,9 +20,11 @@ from http import HTTPStatus from faker import Faker - +from marshmallow import ValidationError +from unittest.mock import patch import pytest +from met_api.services.contact_service import ContactService from met_api.utils.enums import ContentType from tests.utilities.factory_scenarios import TestContactInfo, TestJwtClaims from tests.utilities.factory_utils import factory_auth_header @@ -31,8 +33,13 @@ fake = Faker() +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) @pytest.mark.parametrize('contact_info', [TestContactInfo.contact1]) -def test_create_contact(client, jwt, session, contact_info): # pylint:disable=unused-argument +def test_create_contact(client, jwt, session, contact_info, side_effect, + expected_status): # pylint:disable=unused-argument """Assert that a contact can be POSTed.""" headers = factory_auth_header(jwt=jwt, claims=TestJwtClaims.no_role) rv = client.post('/api/contacts/', data=json.dumps(contact_info), @@ -45,9 +52,24 @@ def test_create_contact(client, jwt, session, contact_info): # pylint:disable=u assert rv.json.get('address') == contact_info.get('address') assert rv.json.get('bio') == contact_info.get('bio') + with patch.object(ContactService, 'create_contact', side_effect=side_effect): + rv = client.post('/api/contacts/', data=json.dumps(contact_info), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status + + with patch.object(ContactService, 'create_contact', side_effect=ValidationError('Test error')): + rv = client.post('/api/contacts/', data=json.dumps(contact_info), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) @pytest.mark.parametrize('contact_info', [TestContactInfo.contact1]) -def test_get_contact(client, jwt, session, contact_info): # pylint:disable=unused-argument +def test_get_contact(client, jwt, session, contact_info, side_effect, + expected_status): # pylint:disable=unused-argument """Assert that a contact can be fetched.""" headers = factory_auth_header(jwt=jwt, claims=TestJwtClaims.no_role) rv = client.post('/api/contacts/', data=json.dumps(contact_info), @@ -58,9 +80,18 @@ def test_get_contact(client, jwt, session, contact_info): # pylint:disable=unus assert rv.status_code == HTTPStatus.OK assert rv.json[0].get('name') == contact_info.get('name') + with patch.object(ContactService, 'get_contacts', side_effect=side_effect): + rv = client.get('/api/contacts/', headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status + +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) @pytest.mark.parametrize('contact_info', [TestContactInfo.contact1]) -def test_patch_contact(client, jwt, session, contact_info): # pylint:disable=unused-argument +def test_patch_contact(client, jwt, session, contact_info, side_effect, + expected_status): # pylint:disable=unused-argument """Assert that a contact can be PATCHed.""" headers = factory_auth_header(jwt=jwt, claims=TestJwtClaims.no_role) rv = client.post('/api/contacts/', data=json.dumps(contact_info), @@ -85,3 +116,37 @@ def test_patch_contact(client, jwt, session, contact_info): # pylint:disable=un rv = client.get('/api/contacts/', headers=headers, content_type=ContentType.JSON.value) assert rv.status_code == HTTPStatus.OK assert rv.json[0].get('name') == contact_edits.get('name') + + with patch.object(ContactService, 'update_contact', side_effect=side_effect): + rv = client.patch('/api/contacts/', data=json.dumps(contact_edits), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status + + with patch.object(ContactService, 'update_contact', side_effect=ValidationError('Test error')): + rv = client.patch('/api/contacts/', data=json.dumps(contact_edits), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + + +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +@pytest.mark.parametrize('contact_info', [TestContactInfo.contact1]) +def test_get_contact_by_id(client, jwt, session, contact_info, side_effect, + expected_status): # pylint:disable=unused-argument + """Assert that a contact can be POSTed.""" + headers = factory_auth_header(jwt=jwt, claims=TestJwtClaims.no_role) + rv = client.post('/api/contacts/', data=json.dumps(contact_info), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.OK + contact_id = rv.json.get('id') + name = rv.json.get('name') + + rv = client.get(f'/api/contacts/{contact_id}', headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.OK + assert rv.json.get('name') == name + + with patch.object(ContactService, 'get_contact_by_id', side_effect=side_effect): + rv = client.get(f'/api/contacts/{contact_id}', headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status diff --git a/met-api/tests/unit/api/test_email_verification_service.py b/met-api/tests/unit/api/test_email_verification_service.py index 8d09c9de5..87bef2173 100644 --- a/met-api/tests/unit/api/test_email_verification_service.py +++ b/met-api/tests/unit/api/test_email_verification_service.py @@ -18,9 +18,14 @@ """ import json +from http import HTTPStatus from faker import Faker +from unittest.mock import patch +import pytest + from met_api.constants.email_verification import EmailVerificationType from met_api.constants.subscription_type import SubscriptionTypes +from met_api.services.email_verification_service import EmailVerificationService from met_api.utils.enums import ContentType from tests.utilities.factory_scenarios import TestJwtClaims from tests.utilities.factory_utils import ( @@ -45,7 +50,12 @@ def test_email_verification(client, jwt, session, notify_mock, ): # pylint:disa assert rv.status_code == 200 -def test_get_email_verification_by_token(client, jwt, session): # pylint:disable=unused-argument +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_get_email_verification_by_token(client, jwt, session, side_effect, + expected_status): # pylint:disable=unused-argument """Assert that an email verification can be fetched.""" claims = TestJwtClaims.public_user_role set_global_tenant() @@ -60,6 +70,17 @@ def test_get_email_verification_by_token(client, jwt, session): # pylint:disabl assert rv.json.get('verification_token') == email_verification.verification_token assert rv.json.get('is_active') is True + with patch.object(EmailVerificationService, 'get_active', side_effect=side_effect): + rv = client.get(f'/api/email_verification/{email_verification.verification_token}', + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status + + # test email verification not found + email_verification_token = fake.text(max_nb_chars=20) + rv = client.get(f'/api/email_verification/{email_verification_token}', + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + def test_patch_email_verification_by_token(client, jwt, session): # pylint:disable=unused-argument """Assert that an email verification can be fetched.""" @@ -76,8 +97,29 @@ def test_patch_email_verification_by_token(client, jwt, session): # pylint:disa assert rv.json.get('verification_token') == email_verification.verification_token assert rv.json.get('is_active') is False + with patch.object(EmailVerificationService, 'verify', side_effect=KeyError('Test error')): + rv = client.put(f'/api/email_verification/{email_verification.verification_token}', + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.NOT_FOUND + + with patch.object(EmailVerificationService, 'verify', side_effect=ValueError('Test error')): + rv = client.put(f'/api/email_verification/{email_verification.verification_token}', + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR -def test_post_subscription_email_verification(client, jwt, session, notify_mock): # pylint:disable=unused-argument + # test email verification not found to update the data + email_verification_token = fake.text(max_nb_chars=20) + rv = client.put(f'/api/email_verification/{email_verification_token}', + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + + +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_post_subscription_email_verification(client, jwt, session, notify_mock, + side_effect, expected_status): # pylint:disable=unused-argument """Assert that an Subscription Email can be sent.""" claims = TestJwtClaims.public_user_role set_global_tenant() @@ -100,3 +142,9 @@ def test_post_subscription_email_verification(client, jwt, session, notify_mock) assert rv.status_code == 200 assert rv.json.get('type') == EmailVerificationType.Subscribe + + with patch.object(EmailVerificationService, 'create', side_effect=side_effect): + rv = client.post(f'/api/email_verification/{SubscriptionTypes.PROJECT.value}/subscribe', + data=json.dumps(to_dict), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status diff --git a/met-api/tests/unit/api/test_engagement.py b/met-api/tests/unit/api/test_engagement.py index e0effe6fc..7b56d6f35 100644 --- a/met-api/tests/unit/api/test_engagement.py +++ b/met-api/tests/unit/api/test_engagement.py @@ -21,11 +21,14 @@ from http import HTTPStatus import pytest +from unittest.mock import patch from faker import Faker +from marshmallow import ValidationError from flask import current_app from met_api.constants.engagement_status import EngagementDisplayStatus, SubmissionStatus from met_api.models.tenant import Tenant as TenantModel +from met_api.services.engagement_service import EngagementService from met_api.utils.constants import TENANT_ID_HEADER from met_api.utils.enums import ContentType from tests.utilities.factory_scenarios import ( @@ -39,7 +42,11 @@ @pytest.mark.parametrize('engagement_info', [TestEngagementInfo.engagement1]) -def test_add_engagements(client, jwt, session, engagement_info, +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_add_engagements(client, jwt, session, engagement_info, side_effect, expected_status, setup_admin_user_and_claims): # pylint:disable=unused-argument """Assert that an engagement can be POSTed.""" user, claims = setup_admin_user_and_claims @@ -48,6 +55,16 @@ def test_add_engagements(client, jwt, session, engagement_info, headers=headers, content_type=ContentType.JSON.value) assert rv.status_code == 200 + with patch.object(EngagementService, 'create_engagement', side_effect=side_effect): + rv = client.post('/api/engagements/', data=json.dumps(engagement_info), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status + + with patch.object(EngagementService, 'create_engagement', side_effect=ValidationError('Test error')): + rv = client.post('/api/engagements/', data=json.dumps(engagement_info), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + def test_tenant_id_in_create_engagements(client, jwt, session, setup_admin_user_and_claims): # pylint:disable=unused-argument @@ -113,7 +130,11 @@ def test_add_engagements_invalid(client, jwt, session, engagement_info, @pytest.mark.parametrize('engagement_info', [TestEngagementInfo.engagement1]) -def test_get_engagements(client, jwt, session, engagement_info, +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_get_engagements(client, jwt, session, engagement_info, side_effect, expected_status, setup_admin_user_and_claims): # pylint:disable=unused-argument """Assert that an engagement can be POSTed.""" user, claims = setup_admin_user_and_claims @@ -129,6 +150,16 @@ def test_get_engagements(client, jwt, session, engagement_info, assert created_eng.get('name') == rv.json.get('name') assert created_eng.get('content') == rv.json.get('content') + with patch.object(EngagementService, 'get_engagement', side_effect=side_effect): + rv = client.get(f'/api/engagements/{created_eng.get("id")}', data=json.dumps(engagement_info), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status + + engagement_id = fake.pyint() + rv = client.get(f'/api/engagements/{engagement_id}', data=json.dumps(engagement_info), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + @pytest.mark.parametrize('engagement_info', [TestEngagementInfo.engagement_draft]) def test_get_engagements_reviewer(client, jwt, session, engagement_info, @@ -159,8 +190,11 @@ def test_get_engagements_reviewer(client, jwt, session, engagement_info, @pytest.mark.parametrize('engagement_info', [TestEngagementInfo.engagement1]) +@pytest.mark.parametrize('side_effect, expected_status', [ + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) def test_search_engagements_by_status(client, jwt, - session, engagement_info, + session, engagement_info, side_effect, expected_status, setup_admin_user_and_claims): # pylint:disable=unused-argument """Assert that an engagement can be fetched by filtering using the engagement status.""" user, claims = setup_admin_user_and_claims @@ -182,6 +216,13 @@ def test_search_engagements_by_status(client, jwt, assert rv.json.get('total') == 1 + with patch.object(EngagementService, 'get_engagements_paginated', side_effect=side_effect): + rv = client.get(f'/api/engagements/?page={page}&size={page_size}&sort_key={sort_key}\ + &sort_order={sort_order}&engagement_status={[engagement_status]}', + data=json.dumps(engagement_info), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status + def test_search_engagements(client, jwt, session): # pylint:disable=unused-argument """Verify the functionality of searching engagements with different access levels.""" @@ -292,7 +333,11 @@ def test_search_engagements_not_logged_in(client, session): # pylint:disable=un @pytest.mark.parametrize('engagement_info', [TestEngagementInfo.engagement1]) -def test_patch_engagement(client, jwt, session, engagement_info, +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_patch_engagement(client, jwt, session, engagement_info, side_effect, expected_status, setup_admin_user_and_claims): # pylint:disable=unused-argument """Assert that an engagement can be updated.""" user, claims = setup_admin_user_and_claims @@ -325,6 +370,16 @@ def test_patch_engagement(client, jwt, session, engagement_info, assert rv.json.get('content') == engagement_edits.get('content') assert engagement_edits.get('created_date') in rv.json.get('created_date') + with patch.object(EngagementService, 'edit_engagement', side_effect=side_effect): + rv = client.patch('/api/engagements/', data=json.dumps(engagement_edits), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status + + with patch.object(EngagementService, 'edit_engagement', side_effect=ValidationError('Test error')): + rv = client.patch('/api/engagements/', data=json.dumps(engagement_edits), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + def test_patch_engagement_by_member(client, jwt, session): # pylint:disable=unused-argument """Assert that an engagement can be updated.""" diff --git a/met-api/tests/unit/api/test_engagement_membership.py b/met-api/tests/unit/api/test_engagement_membership.py index 6b5805485..711ab3bd8 100644 --- a/met-api/tests/unit/api/test_engagement_membership.py +++ b/met-api/tests/unit/api/test_engagement_membership.py @@ -5,9 +5,12 @@ """ import json from http import HTTPStatus -from unittest.mock import MagicMock +from unittest.mock import MagicMock, patch +import pytest from met_api.constants.membership_type import MembershipType +from met_api.exceptions.business_exception import BusinessException +from met_api.services.membership_service import MembershipService from met_api.utils.enums import ContentType, KeycloakGroupName, MembershipStatus from tests.utilities.factory_utils import ( factory_auth_header, factory_engagement_model, factory_membership_model, factory_staff_user_model) @@ -51,6 +54,16 @@ def test_create_engagement_membership_team_member(mocker, client, jwt, session, mock_add_user_to_group_keycloak.assert_called() mock_get_users_groups_keycloak.assert_called() + with patch.object(MembershipService, 'create_membership', + side_effect=BusinessException('Test error', status_code=HTTPStatus.INTERNAL_SERVER_ERROR)): + rv = client.post( + memberships_url.format(engagement.id), + data=json.dumps(data), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + def test_create_engagement_membership_reviewer(mocker, client, jwt, session, setup_admin_user_and_claims): @@ -222,3 +235,73 @@ def reinstate_already_active_membership(client, jwt, session, ) assert rv.status_code == HTTPStatus.BAD_REQUEST + + +def test_get_membership(client, jwt, session, + setup_admin_user_and_claims): + """Test that a membership can be fetched.""" + user, claims = setup_admin_user_and_claims + engagement = factory_engagement_model() + staff_user = factory_staff_user_model() + membership = factory_membership_model(user_id=staff_user.id, engagement_id=engagement.id) + headers = factory_auth_header(jwt=jwt, claims=claims) + + rv = client.get( + f'/api/engagements/{engagement.id}/members', + headers=headers, + content_type=ContentType.JSON.value + ) + + assert rv.status_code == HTTPStatus.OK + assert rv.json[0].get('engagement_id') == membership.engagement_id + + with patch.object(MembershipService, 'get_memberships', + side_effect=BusinessException('Test error', status_code=HTTPStatus.INTERNAL_SERVER_ERROR)): + rv = client.get( + f'/api/engagements/{engagement.id}/members', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + + +@pytest.mark.parametrize('side_effect, expected_status', [ + (ValueError('Test error'), HTTPStatus.BAD_REQUEST), +]) +def test_get_all_engagements_by_user(mocker, client, jwt, session, side_effect, expected_status, + setup_admin_user_and_claims): + """Test that all engagements can be fetched for a member.""" + user, claims = setup_admin_user_and_claims + engagement = factory_engagement_model() + staff_user = factory_staff_user_model() + headers = factory_auth_header(jwt=jwt, claims=claims) + + mock_add_user_to_group_keycloak_response = MagicMock() + mock_add_user_to_group_keycloak_response.status_code = HTTPStatus.NO_CONTENT + mocker.patch( + 'met_api.services.keycloak.KeycloakService.add_user_to_group', + return_value=mock_add_user_to_group_keycloak_response + ) + mocker.patch( + 'met_api.services.keycloak.KeycloakService.get_users_groups', + return_value={staff_user.external_id: [KeycloakGroupName.EAO_TEAM_MEMBER.value]} + ) + + data = {'user_id': staff_user.external_id} + + rv = client.post( + memberships_url.format(engagement.id), + data=json.dumps(data), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.OK + + rv = client.get( + f'/api/engagements/all/members/{staff_user.external_id}', + headers=headers, + content_type=ContentType.JSON.value + ) + + assert rv.status_code == HTTPStatus.OK + assert rv.json[0].get('engagement_id') == engagement.id diff --git a/met-api/tests/unit/api/test_engagement_settings.py b/met-api/tests/unit/api/test_engagement_settings.py index 22deabbb4..f0b0932d6 100644 --- a/met-api/tests/unit/api/test_engagement_settings.py +++ b/met-api/tests/unit/api/test_engagement_settings.py @@ -21,8 +21,12 @@ from http import HTTPStatus from faker import Faker +from unittest.mock import patch +import pytest +from marshmallow import ValidationError from met_api.constants.engagement_status import Status +from met_api.services.engagement_settings_service import EngagementSettingsService from met_api.utils.enums import ContentType from tests.utilities.factory_scenarios import TestJwtClaims from tests.utilities.factory_utils import ( @@ -32,7 +36,11 @@ fake = Faker() -def test_get_engagement_settings(client, jwt, session, +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_get_engagement_settings(client, jwt, session, side_effect, expected_status, setup_admin_user_and_claims): # pylint:disable=unused-argument """Assert that engagement settings can be fetched.""" user, claims = setup_admin_user_and_claims @@ -51,6 +59,14 @@ def test_get_engagement_settings(client, jwt, session, response_data = rv.json assert response_data.get('send_report') == engagement_settings.send_report + with patch.object(EngagementSettingsService, 'get', side_effect=side_effect): + rv = client.get( + f'/api/engagementsettings/{engagement.id}', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == expected_status + def test_get_engagement_settings_for_draft_engagement(client, jwt, session, setup_admin_user_and_claims): # pylint:disable=unused-argument @@ -80,7 +96,11 @@ def test_get_engagement_settings_for_draft_engagement(client, jwt, session, assert rv.status_code == HTTPStatus.FORBIDDEN, 'Not a team member.So throws exception.' -def test_patch_engagement_settings(client, jwt, session, +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_patch_engagement_settings(client, jwt, session, side_effect, expected_status, setup_admin_user_and_claims): # pylint:disable=unused-argument """Assert that engagement settings can be PATCHed.""" user, claims = setup_admin_user_and_claims @@ -112,3 +132,21 @@ def test_patch_engagement_settings(client, jwt, session, assert rv.status_code == HTTPStatus.OK response_data = rv.json assert response_data.get('send_report') == patch_data.get('send_report') + + with patch.object(EngagementSettingsService, 'update_settings', side_effect=side_effect): + rv = client.patch( + '/api/engagementsettings/', + data=json.dumps(patch_data), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == expected_status + + with patch.object(EngagementSettingsService, 'update_settings', side_effect=ValidationError('Test error')): + rv = client.patch( + '/api/engagementsettings/', + data=json.dumps(patch_data), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR diff --git a/met-api/tests/unit/api/test_engagement_slug.py b/met-api/tests/unit/api/test_engagement_slug.py index 88f6009ca..7ae220e2d 100644 --- a/met-api/tests/unit/api/test_engagement_slug.py +++ b/met-api/tests/unit/api/test_engagement_slug.py @@ -21,8 +21,10 @@ import pytest from faker import Faker +from unittest.mock import patch from met_api.constants.engagement_status import Status +from met_api.services.engagement_slug_service import EngagementSlugService from met_api.utils.enums import ContentType from tests.utilities.factory_scenarios import TestEngagementSlugInfo, TestJwtClaims, TestUserInfo from tests.utilities.factory_utils import factory_auth_header, factory_engagement_model, factory_engagement_slug_model @@ -32,7 +34,12 @@ @pytest.mark.parametrize('engagement_slug_info', [TestEngagementSlugInfo.slug1]) -def test_get_engagement_slug(client, jwt, session, engagement_slug_info): +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.BAD_REQUEST), + (ValueError('Test error'), HTTPStatus.BAD_REQUEST), +]) +def test_get_engagement_slug(client, jwt, session, side_effect, expected_status, + engagement_slug_info): """Test get request for engagement_slug endpoint.""" eng = factory_engagement_model() engagement_slug_info = { @@ -46,9 +53,18 @@ def test_get_engagement_slug(client, jwt, session, engagement_slug_info): assert rv.json.get('slug') == eng_slug.slug assert rv.json.get('engagement_id') == eng_slug.engagement_id + with patch.object(EngagementSlugService, 'get_engagement_slug', side_effect=side_effect): + rv = client.get(f'/api/slugs/{eng_slug.slug}', headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status + @pytest.mark.parametrize('engagement_slug_info', [TestEngagementSlugInfo.slug1]) -def test_get_engagement_slug_by_engagement_id(client, jwt, session, engagement_slug_info): +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.BAD_REQUEST), + (ValueError('Test error'), HTTPStatus.BAD_REQUEST), +]) +def test_get_engagement_slug_by_engagement_id(client, jwt, session, side_effect, expected_status, + engagement_slug_info): """Test get request for engagement_slug endpoint.""" eng = factory_engagement_model() engagement_slug_info = { @@ -62,6 +78,11 @@ def test_get_engagement_slug_by_engagement_id(client, jwt, session, engagement_s assert rv.json.get('slug') == eng_slug.slug assert rv.json.get('engagement_id') == eng_slug.engagement_id + with patch.object(EngagementSlugService, 'get_engagement_slug_by_engagement_id', side_effect=side_effect): + rv = client.get(f'/api/slugs/engagements/{eng.id}', + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status + def test_get_nonexistent_engagement_slug(client, jwt, session): """Test get request for non-existent engagement_slug endpoint.""" @@ -71,7 +92,11 @@ def test_get_nonexistent_engagement_slug(client, jwt, session): @pytest.mark.parametrize('engagement_slug_info', [TestEngagementSlugInfo.slug1]) -def test_patch_engagement_slug(client, jwt, session, engagement_slug_info, +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.BAD_REQUEST), + (ValueError('Test error'), HTTPStatus.BAD_REQUEST), +]) +def test_patch_engagement_slug(client, jwt, session, engagement_slug_info, side_effect, expected_status, setup_admin_user_and_claims): """Test patch request for engagement_slug endpoint.""" user, claims = setup_admin_user_and_claims @@ -91,6 +116,11 @@ def test_patch_engagement_slug(client, jwt, session, engagement_slug_info, headers=headers, content_type=ContentType.JSON.value) assert rv.status_code == HTTPStatus.OK + with patch.object(EngagementSlugService, 'update_engagement_slug', side_effect=side_effect): + rv = client.patch(f'/api/slugs/{updated_slug}', data=json.dumps(patch_data), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status + def test_patch_create_nonexistent_engagement_slug(client, jwt, session, setup_admin_user_and_claims): diff --git a/met-api/tests/unit/api/test_feedback.py b/met-api/tests/unit/api/test_feedback.py index f86823fb8..66cc49aea 100644 --- a/met-api/tests/unit/api/test_feedback.py +++ b/met-api/tests/unit/api/test_feedback.py @@ -17,15 +17,25 @@ Test-Suite to ensure that the /Feedbacks endpoint is working as expected. """ import json +from http import HTTPStatus +from unittest.mock import patch +from faker import Faker +import pytest from met_api.constants.feedback import FeedbackSourceType, FeedbackStatusType +from met_api.services.feedback_service import FeedbackService from met_api.utils.enums import ContentType - from tests.utilities.factory_scenarios import TestJwtClaims from tests.utilities.factory_utils import factory_auth_header, factory_feedback_model +fake = Faker() + -def test_feedback(client, jwt, session): # pylint:disable=unused-argument +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_feedback(client, jwt, session, side_effect, expected_status,): # pylint:disable=unused-argument """Assert that an feedback can be POSTed.""" claims = TestJwtClaims.public_user_role @@ -50,6 +60,11 @@ def test_feedback(client, jwt, session): # pylint:disable=unused-argument assert result.get('comment') == feedback.comment assert result.get('source') == FeedbackSourceType.Internal + with patch.object(FeedbackService, 'create_feedback', side_effect=side_effect): + rv = client.post('/api/feedbacks/', data=json.dumps(to_dict), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status + def test_invalid_feedback(client, jwt, session): # pylint:disable=unused-argument """Assert that an invalid feedback can not be POSTed.""" @@ -103,8 +118,18 @@ def test_patch_feedback(client, jwt, session): # pylint:disable=unused-argument # Check if the status is update assert rv.json.get('status') == FeedbackStatusType.Archived.value + # Patching a non existing feedback should give an error + feedback_id = fake.pyint() + rv = client.patch(f'/api/feedbacks/{feedback_id}', data=json.dumps(feedback_creation), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.NOT_FOUND + -def test_delete_feedback(client, jwt, session): # pylint:disable=unused-argument +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_delete_feedback(client, jwt, session, side_effect, expected_status,): # pylint:disable=unused-argument """Assert that feedback can be deleted.""" # Setup: Create a new feedback first claims = TestJwtClaims.public_user_role @@ -123,3 +148,44 @@ def test_delete_feedback(client, jwt, session): # pylint:disable=unused-argumen # Now, delete this feedback rv = client.delete(f'/api/feedbacks/{feedback_id}', headers=headers) assert rv.status_code == 200 + + # Delete a non existing feedback + rv = client.delete(f'/api/feedbacks/{feedback_id}', headers=headers) + assert rv.status_code == HTTPStatus.NOT_FOUND + + rv = client.post('/api/feedbacks/', data=json.dumps(feedback_creation), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == 200 + with patch.object(FeedbackService, 'delete_feedback', side_effect=side_effect): + rv = client.delete(f'/api/feedbacks/{feedback_id}', headers=headers) + assert rv.status_code == expected_status + + +@pytest.mark.parametrize('side_effect, expected_status', [ + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_get_feedback(client, jwt, session, side_effect, expected_status,): # pylint:disable=unused-argument + """Assert that feedback can be fetched.""" + # Setup: Create a new feedback first + claims = TestJwtClaims.public_user_role + feedback = factory_feedback_model() + headers = factory_auth_header(jwt=jwt, claims=claims) + + page = 1 + page_size = 10 + sort_key = 'created_date' + sort_order = 'desc' + feedback_status = feedback.status + + rv = client.get(f'/api/feedbacks/?page={page}&size={page_size}&sort_key={sort_key}\ + &sort_order={sort_order}&engagement_status={[feedback_status]}', + headers=headers, content_type=ContentType.JSON.value) + + assert rv.status_code == 200 + assert rv.json.get('total') == 1 + + with patch.object(FeedbackService, 'get_feedback_paginated', side_effect=side_effect): + rv = client.get(f'/api/feedbacks/?page={page}&size={page_size}&sort_key={sort_key}\ + &sort_order={sort_order}&engagement_status={[feedback_status]}', + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status diff --git a/met-api/tests/unit/api/test_report_setting.py b/met-api/tests/unit/api/test_report_setting.py index c95b92728..8f8738ed4 100644 --- a/met-api/tests/unit/api/test_report_setting.py +++ b/met-api/tests/unit/api/test_report_setting.py @@ -18,13 +18,22 @@ """ import json from http import HTTPStatus +from unittest.mock import patch +import pytest +from marshmallow import ValidationError + +from met_api.services.report_setting_service import ReportSettingService from met_api.utils.enums import ContentType from tests.utilities.factory_scenarios import TestJwtClaims, TestReportSettingInfo, TestSurveyInfo from tests.utilities.factory_utils import ( factory_auth_header, factory_survey_and_eng_model, factory_survey_report_setting_model) -def test_get_report_setting(client, jwt, session): # pylint:disable=unused-argument +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_get_report_setting(client, jwt, session, side_effect, expected_status): # pylint:disable=unused-argument """Assert that report setting can be fetched.""" headers = factory_auth_header(jwt=jwt, claims=TestJwtClaims.staff_admin_role) survey, _ = factory_survey_and_eng_model(TestSurveyInfo.survey3) @@ -43,8 +52,20 @@ def test_get_report_setting(client, jwt, session): # pylint:disable=unused-argu assert rv.status_code == HTTPStatus.OK + with patch.object(ReportSettingService, 'get_report_setting', side_effect=side_effect): + rv = client.get( + f'/api/surveys/{survey.id}/reportsettings', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == expected_status + -def test_patch_report_setting(client, jwt, session): # pylint:disable=unused-argument +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_patch_report_setting(client, jwt, session, side_effect, expected_status): # pylint:disable=unused-argument """Assert that report setting can be PATCHed.""" headers = factory_auth_header(jwt=jwt, claims=TestJwtClaims.staff_admin_role) survey, _ = factory_survey_and_eng_model(TestSurveyInfo.survey3) @@ -83,3 +104,21 @@ def test_patch_report_setting(client, jwt, session): # pylint:disable=unused-ar ) assert rv.status_code == HTTPStatus.OK assert rv.json[0].get('display') is False + + with patch.object(ReportSettingService, 'update_report_setting', side_effect=side_effect): + rv = client.patch( + f'/api/surveys/{survey.id}/reportsettings', + data=json.dumps([report_setting_edits]), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == expected_status + + with patch.object(ReportSettingService, 'update_report_setting', side_effect=ValidationError('Test error')): + rv = client.patch( + f'/api/surveys/{survey.id}/reportsettings', + data=json.dumps([report_setting_edits]), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR diff --git a/met-api/tests/unit/api/test_submission.py b/met-api/tests/unit/api/test_submission.py index b70f69e9d..724a55902 100644 --- a/met-api/tests/unit/api/test_submission.py +++ b/met-api/tests/unit/api/test_submission.py @@ -18,10 +18,14 @@ """ import copy import json +from http import HTTPStatus +from unittest.mock import patch import pytest +from faker import Faker from met_api.constants.membership_type import MembershipType +from met_api.services.submission_service import SubmissionService from met_api.utils.enums import ContentType from tests.utilities.factory_scenarios import TestJwtClaims, TestSubmissionInfo from tests.utilities.factory_utils import ( @@ -31,9 +35,14 @@ DATE_FORMAT = '%Y-%m-%d %H:%M:%S' +fake = Faker() -def test_valid_submission(client, jwt, session): # pylint:disable=unused-argument +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_valid_submission(client, jwt, session, side_effect, expected_status): # pylint:disable=unused-argument """Assert that an engagement can be POSTed.""" claims = TestJwtClaims.public_user_role @@ -50,6 +59,12 @@ def test_valid_submission(client, jwt, session): # pylint:disable=unused-argume headers=headers, content_type=ContentType.JSON.value) assert rv.status_code == 200 + with patch.object(SubmissionService, 'create', side_effect=side_effect): + rv = client.post(f'/api/submissions/public/{email_verification.verification_token}', + data=json.dumps(to_dict), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status + @pytest.mark.parametrize('submission_info', [TestSubmissionInfo.submission1]) def test_get_submission_by_id(client, jwt, session, submission_info, diff --git a/met-api/tests/unit/api/test_subscription.py b/met-api/tests/unit/api/test_subscription.py index cac609450..034df4e64 100644 --- a/met-api/tests/unit/api/test_subscription.py +++ b/met-api/tests/unit/api/test_subscription.py @@ -18,14 +18,27 @@ """ import json +from http import HTTPStatus +from faker import Faker +from unittest.mock import patch +import pytest + +from met_api.services.subscription_service import SubscriptionService from met_api.utils.enums import ContentType from tests.utilities.factory_scenarios import TestJwtClaims from tests.utilities.factory_utils import ( factory_auth_header, factory_participant_model, factory_subscription_model, factory_survey_and_eng_model, set_global_tenant) +fake = Faker() + -def test_create_subscription(client, jwt, session): # pylint:disable=unused-argument +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_create_subscription(client, jwt, session, side_effect, + expected_status): # pylint:disable=unused-argument """Assert that an Email can be sent.""" claims = TestJwtClaims.public_user_role set_global_tenant() @@ -40,11 +53,21 @@ def test_create_subscription(client, jwt, session): # pylint:disable=unused-arg rv = client.post('/api/subscription/', data=json.dumps(to_dict), headers=headers, content_type=ContentType.JSON.value) - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value + with patch.object(SubscriptionService, 'create_subscription', side_effect=side_effect): + rv = client.post('/api/subscription/', data=json.dumps(to_dict), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status -def test_update_subscription(client, jwt, session): # pylint:disable=unused-argument - """Assert that an subscription can be updated.""" + +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_update_subscription(client, jwt, session, side_effect, + expected_status): # pylint:disable=unused-argument + """Assert that a subscription can be updated.""" headers = factory_auth_header(jwt=jwt, claims=TestJwtClaims.public_user_role) subscription = factory_subscription_model() subscription_participant_id = str(subscription.participant_id) @@ -57,11 +80,21 @@ def test_update_subscription(client, jwt, session): # pylint:disable=unused-arg rv = client.patch('/api/subscription/', data=json.dumps(subscription_edits), headers=headers, content_type=ContentType.JSON.value) - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value + + with patch.object(SubscriptionService, 'update_subscription_for_participant', side_effect=side_effect): + rv = client.patch('/api/subscription/', data=json.dumps(subscription_edits), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status -def test_get_subscription(client, jwt, session): # pylint:disable=unused-argument - """Assert that an subscription can be fetched.""" +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_get_subscription(client, jwt, session, side_effect, + expected_status): # pylint:disable=unused-argument + """Assert that a subscription can be fetched.""" headers = factory_auth_header(jwt=jwt, claims=TestJwtClaims.public_user_role) subscription = factory_subscription_model() subscription_participant_id = str(subscription.participant_id) @@ -69,5 +102,75 @@ def test_get_subscription(client, jwt, session): # pylint:disable=unused-argume rv = client.get(f'/api/subscription/{subscription_participant_id}', headers=headers, content_type=ContentType.JSON.value) - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value assert rv.json.get('participant_id') == subscription.participant_id + + with patch.object(SubscriptionService, 'get', side_effect=side_effect): + rv = client.get(f'/api/subscription/{subscription_participant_id}', + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status + + # test subscription not found + subscription_participant_id = fake.pyint() + rv = client.get(f'/api/subscription/{subscription_participant_id}', + headers=headers, content_type=ContentType.JSON.value) + + assert rv.status_code == HTTPStatus.NOT_FOUND.value + + +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_confirm_subscription(client, jwt, session, side_effect, + expected_status): # pylint:disable=unused-argument + """Assert that a subscription can be confirmed or unsubscribed.""" + claims = TestJwtClaims.public_user_role + set_global_tenant() + survey, eng = factory_survey_and_eng_model() + participant = factory_participant_model() + to_dict = { + 'engagement_id': eng.id, + 'participant_id': participant.id, + 'is_subscribed': True, + } + headers = factory_auth_header(jwt=jwt, claims=claims) + rv = client.post('/api/subscription/manage', data=json.dumps(to_dict), + headers=headers, content_type=ContentType.JSON.value) + + assert rv.status_code == HTTPStatus.OK.value + + subscription_participant_id = str(participant.id) + + rv = client.get(f'/api/subscription/{subscription_participant_id}', + headers=headers, content_type=ContentType.JSON.value) + + assert rv.status_code == HTTPStatus.OK.value + assert rv.json.get('is_subscribed') is True + + with patch.object(SubscriptionService, 'create_or_update_subscription', side_effect=side_effect): + rv = client.post('/api/subscription/manage', data=json.dumps(to_dict), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status + + subscription_edits = { + 'engagement_id': eng.id, + 'participant_id': participant.id, + 'is_subscribed': False, + } + + rv = client.patch('/api/subscription/manage', data=json.dumps(subscription_edits), + headers=headers, content_type=ContentType.JSON.value) + + assert rv.status_code == 200 + + rv = client.get(f'/api/subscription/{subscription_participant_id}', + headers=headers, content_type=ContentType.JSON.value) + + assert rv.status_code == HTTPStatus.OK.value + assert rv.json.get('is_subscribed') is False + + with patch.object(SubscriptionService, 'update_subscription_for_participant_eng', side_effect=side_effect): + rv = client.patch('/api/subscription/manage', data=json.dumps(subscription_edits), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status diff --git a/met-api/tests/unit/api/test_survey.py b/met-api/tests/unit/api/test_survey.py index 29eebeea0..1f47fa918 100644 --- a/met-api/tests/unit/api/test_survey.py +++ b/met-api/tests/unit/api/test_survey.py @@ -20,16 +20,20 @@ import json from http import HTTPStatus +from unittest.mock import patch import pytest from flask import current_app from met_api.constants.engagement_status import Status +from met_api.exceptions.business_exception import BusinessException from met_api.models.engagement import Engagement as EngagementModel from met_api.models.membership import Membership as MembershipModel from met_api.models.tenant import Tenant as TenantModel +from met_api.services.survey_service import SurveyService from met_api.utils.constants import TENANT_ID_HEADER from met_api.utils.enums import ContentType, MembershipStatus -from tests.utilities.factory_scenarios import TestJwtClaims, TestSurveyInfo, TestTenantInfo, TestUserInfo +from tests.utilities.factory_scenarios import ( + TestEngagementInfo, TestJwtClaims, TestSurveyInfo, TestTenantInfo, TestUserInfo) from tests.utilities.factory_utils import ( factory_auth_header, factory_engagement_model, factory_membership_model, factory_staff_user_model, factory_survey_model, factory_tenant_model, set_global_tenant) @@ -39,7 +43,11 @@ @pytest.mark.parametrize('survey_info', [TestSurveyInfo.survey1]) -def test_create_survey(client, jwt, session, survey_info, +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_create_survey(client, jwt, session, survey_info, side_effect, expected_status, setup_admin_user_and_claims): # pylint:disable=unused-argument """Assert that an survey can be POSTed.""" user, claims = setup_admin_user_and_claims @@ -50,9 +58,14 @@ def test_create_survey(client, jwt, session, survey_info, } rv = client.post(surveys_url, data=json.dumps(data), headers=headers, content_type=ContentType.JSON.value) - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value assert rv.json.get('form_json') == survey_info.get('form_json') + with patch.object(SurveyService, 'create', side_effect=side_effect): + rv = client.post(surveys_url, data=json.dumps(data), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status + def test_create_survey_with_tenant(client, jwt, session, setup_admin_user_and_claims): # pylint:disable=unused-argument @@ -68,7 +81,7 @@ def test_create_survey_with_tenant(client, jwt, session, 'name': TestSurveyInfo.survey1.get('name'), 'display': TestSurveyInfo.survey1.get('form_json').get('display'), }), headers=headers, content_type=ContentType.JSON.value) - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value survey_tenant_id = rv.json.get('tenant_id') assert survey_tenant_id == str(tenant.id) @@ -103,7 +116,7 @@ def test_create_survey_with_tenant(client, jwt, session, 'name': TestSurveyInfo.survey2.get('name'), 'display': TestSurveyInfo.survey2.get('form_json').get('display'), }), headers=headers, content_type=ContentType.JSON.value) - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value # Verify that the new survey belongs to the correct tenant survey_tenant_id = rv.json.get('tenant_id') @@ -111,7 +124,11 @@ def test_create_survey_with_tenant(client, jwt, session, @pytest.mark.parametrize('survey_info', [TestSurveyInfo.survey2]) -def test_put_survey(client, jwt, session, survey_info, +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_put_survey(client, jwt, session, survey_info, side_effect, expected_status, setup_admin_user_and_claims): # pylint:disable=unused-argument """Assert that an survey can be POSTed.""" user, claims = setup_admin_user_and_claims @@ -122,16 +139,31 @@ def test_put_survey(client, jwt, session, survey_info, rv = client.put(surveys_url, data=json.dumps({'id': survey_id, 'name': new_survey_name}), headers=headers, content_type=ContentType.JSON.value) - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value rv = client.get(f'{surveys_url}{survey_id}', headers=headers, content_type=ContentType.JSON.value) - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value assert rv.json.get('form_json') == survey_info.get('form_json') assert rv.json.get('name') == new_survey_name + with patch.object(SurveyService, 'update', side_effect=side_effect): + rv = client.put(surveys_url, data=json.dumps({'id': survey_id, 'name': new_survey_name}), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status + + with patch.object(SurveyService, 'update', + side_effect=BusinessException('Test error', status_code=HTTPStatus.INTERNAL_SERVER_ERROR)): + rv = client.put(surveys_url, data=json.dumps({'id': survey_id, 'name': new_survey_name}), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR -def test_survey_link(client, jwt, session, + +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_survey_link(client, jwt, session, side_effect, expected_status, setup_admin_user_and_claims): # pylint:disable=unused-argument """Assert that a survey can be POSTed.""" user, claims = setup_admin_user_and_claims @@ -157,6 +189,14 @@ def test_survey_link(client, jwt, session, content_type=ContentType.JSON.value ) + with patch.object(SurveyService, 'link', side_effect=side_effect): + rv = client.put( + f'{surveys_url}{survey_id}/link/engagement/{eng_id}', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == expected_status + rv = client.get( f'{surveys_url}{survey_id}', headers=headers, @@ -164,6 +204,22 @@ def test_survey_link(client, jwt, session, ) assert rv.json.get('engagement_id') == str(eng_id) + with patch.object(SurveyService, 'get', side_effect=side_effect): + rv = client.get( + f'{surveys_url}{survey_id}', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == expected_status + + # test if public user can fetch open surveys + rv = client.get( + f'{surveys_url}{survey_id}', + headers=factory_auth_header(jwt=jwt, claims=TestJwtClaims.public_user_role), + content_type=ContentType.JSON.value + ) + assert rv.json.get('engagement_id') == str(eng_id) + def test_get_hidden_survey_for_admins(client, jwt, session): # pylint:disable=unused-argument """Assert that a hidden survey can be fetched by admins.""" @@ -179,7 +235,7 @@ def test_get_hidden_survey_for_admins(client, jwt, session): # pylint:disable=u rv = client.get(f'{surveys_url}?page={page}&size={page_size}&sort_key={sort_key}\ &sort_order={sort_order}&search_text=', headers=headers, content_type=ContentType.JSON.value) - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value assert rv.json.get('total') == 1 @@ -214,7 +270,7 @@ def test_get_survey_for_reviewer(client, jwt, session): # pylint:disable=unused # Assert Reviewer can see the survey since he is added to the team. rv = client.get(f'{surveys_url}{survey1.id}', headers=headers, content_type=ContentType.JSON.value) - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value # Deactivate membership membership_model: MembershipModel = MembershipModel.find_by_engagement_and_user_id(eng.id, user.id) @@ -233,7 +289,7 @@ def test_get_survey_for_reviewer(client, jwt, session): # pylint:disable=unused headers=headers, content_type=ContentType.JSON.value) # Assert user can access the survey even when he is removed from the team since its published. - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value def test_get_hidden_survey_for_team_member(client, jwt, session): # pylint:disable=unused-argument @@ -250,7 +306,7 @@ def test_get_hidden_survey_for_team_member(client, jwt, session): # pylint:disa rv = client.get(f'{surveys_url}?page={page}&size={page_size}&sort_key={sort_key}\ &sort_order={sort_order}&search_text=', headers=headers, content_type=ContentType.JSON.value) - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value assert rv.json.get('total') == 0 @@ -268,7 +324,7 @@ def test_get_template_survey(client, jwt, session): # pylint:disable=unused-arg rv = client.get(f'{surveys_url}?page={page}&size={page_size}&sort_key={sort_key}\ &sort_order={sort_order}&search_text=', headers=headers, content_type=ContentType.JSON.value) - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value assert rv.json.get('total') == 1 @@ -283,7 +339,7 @@ def test_edit_template_survey_for_admins(client, jwt, session, rv = client.put(surveys_url, data=json.dumps({'id': survey_id, 'name': new_survey_name}), headers=headers, content_type=ContentType.JSON.value) - assert rv.status_code == 200, 'Admins are able to edit template surveys' + assert rv.status_code == HTTPStatus.OK.value, 'Admins are able to edit template surveys' def test_edit_template_survey_for_team_member(client, jwt, session): # pylint:disable=unused-argument @@ -356,3 +412,65 @@ def test_surveys_clone_team_member(mocker, client, jwt, session, survey_info, # Assert the response status code and data assert response.status_code == HTTPStatus.OK assert response.get_json().get('form_json') == survey.form_json + + +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_survey_unlink(client, jwt, session, side_effect, expected_status, + setup_admin_user_and_claims): # pylint:disable=unused-argument + """Assert that a survey can be unlinked from an engagement.""" + user, claims = setup_admin_user_and_claims + survey = factory_survey_model() + survey_id = survey.id + headers = factory_auth_header(jwt=jwt, claims=claims) + + eng = factory_engagement_model(TestEngagementInfo.engagement_draft) + eng_id = eng.id + + # assert eng id is none in GET Survey + rv = client.get( + f'{surveys_url}{survey_id}', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.json.get('engagement_id') is None + + # link them together + rv = client.put( + f'{surveys_url}{survey_id}/link/engagement/{eng_id}', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.OK + + rv = client.get( + f'{surveys_url}{survey_id}', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.json.get('engagement_id') == str(eng_id) + + # unlink the survey + rv = client.delete( + f'{surveys_url}{survey_id}/unlink/engagement/{eng_id}', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.OK + + rv = client.get( + f'{surveys_url}{survey_id}', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.json.get('engagement_id') is None + + with patch.object(SurveyService, 'unlink', side_effect=side_effect): + rv = client.delete( + f'{surveys_url}{survey_id}/unlink/engagement/{eng_id}', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == expected_status diff --git a/met-api/tests/unit/api/test_tenant.py b/met-api/tests/unit/api/test_tenant.py new file mode 100644 index 000000000..b395612be --- /dev/null +++ b/met-api/tests/unit/api/test_tenant.py @@ -0,0 +1,45 @@ +# Copyright © 2019 Province of British Columbia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Tests to verify the tenant API end-point. + +Test-Suite to ensure that the tenant endpoint is working as expected. +""" +from http import HTTPStatus +from unittest.mock import patch + +from met_api.services.tenant_service import TenantService +from met_api.utils.enums import ContentType +from tests.utilities.factory_scenarios import TestJwtClaims, TestTenantInfo +from tests.utilities.factory_utils import factory_auth_header, factory_tenant_model + + +def test_get_tenant(client, jwt, session): # pylint:disable=unused-argument + """Assert that a tenant can be fetched.""" + claims = TestJwtClaims.public_user_role + + tenant_data = TestTenantInfo.tenant1 + factory_tenant_model(tenant_data) + tenant_short_name = tenant_data['short_name'] + + headers = factory_auth_header(jwt=jwt, claims=claims) + rv = client.get(f'/api/tenants/{tenant_short_name}', headers=headers, content_type=ContentType.JSON.value) + + assert rv.status_code == HTTPStatus.OK.value + assert rv.json.get('name') == tenant_data['name'] + + with patch.object(TenantService, 'get', side_effect=ValueError('Test error')): + rv = client.get(f'/api/tenants/{tenant_short_name}', + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR diff --git a/met-api/tests/unit/api/test_user.py b/met-api/tests/unit/api/test_user.py index f7cffe9a3..d95e29556 100644 --- a/met-api/tests/unit/api/test_user.py +++ b/met-api/tests/unit/api/test_user.py @@ -19,11 +19,14 @@ """ import copy from http import HTTPStatus -from unittest.mock import MagicMock - +from unittest.mock import MagicMock, patch +import pytest from flask import current_app +from met_api.exceptions.business_exception import BusinessException from met_api.models import Tenant as TenantModel +from met_api.services.staff_user_membership_service import StaffUserMembershipService +from met_api.services.staff_user_service import StaffUserService from met_api.utils.enums import ContentType, KeycloakGroupName, UserStatus from tests.utilities.factory_scenarios import TestJwtClaims, TestUserInfo from tests.utilities.factory_utils import factory_auth_header, factory_staff_user_model, set_global_tenant @@ -56,7 +59,11 @@ def mock_add_user_to_group(mocker, mock_group_names): return mock_add_user_to_group_keycloak, mock_get_user_groups_keycloak, mock_add_attribute_to_user -def test_create_staff_user(client, jwt, session): +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_create_staff_user(client, jwt, session, side_effect, expected_status): """Assert that a user can be POSTed.""" claims = TestJwtClaims.staff_admin_role headers = factory_auth_header(jwt=jwt, claims=claims) @@ -67,6 +74,10 @@ def test_create_staff_user(client, jwt, session): tenant = TenantModel.find_by_short_name(tenant_short_name) assert rv.json.get('tenant_id') == str(tenant.id) + with patch.object(StaffUserService, 'create_or_update_user', side_effect=side_effect): + rv = client.put('/api/user/', headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == expected_status + def test_get_staff_users(client, jwt, session, setup_admin_user_and_claims): @@ -85,7 +96,11 @@ def test_get_staff_users(client, jwt, session, assert len(rv.json.get('items')) == 4 -def test_add_user_to_admin_group(mocker, client, jwt, session, +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_add_user_to_admin_group(mocker, client, jwt, session, side_effect, expected_status, setup_admin_user_and_claims): """Assert that a user can be added to the admin group.""" user = factory_staff_user_model() @@ -107,6 +122,23 @@ def test_add_user_to_admin_group(mocker, client, jwt, session, mock_get_user_groups_keycloak.assert_called() mock_add_attribute_to_user.assert_called() + with patch.object(StaffUserService, 'add_user_to_group', side_effect=side_effect): + rv = client.post( + f'/api/user/{user.external_id}/groups?group=Administrator', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == expected_status + + with patch.object(StaffUserService, 'add_user_to_group', + side_effect=BusinessException('Test error', status_code=HTTPStatus.INTERNAL_SERVER_ERROR)): + rv = client.post( + f'/api/user/{user.external_id}/groups?group=Administrator', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + def test_add_user_to_reviewer_group(mocker, client, jwt, session, setup_admin_user_and_claims): @@ -277,3 +309,40 @@ def test_toggle_user_active_status_empty_body(mocker, client, jwt, session, ) assert rv.status_code == HTTPStatus.BAD_REQUEST mocked_toggle_user_status.assert_not_called() + + +def test_get_staff_users_by_id(client, jwt, session, + setup_admin_user_and_claims): + """Assert that a user can be fetched.""" + user, claims = setup_admin_user_and_claims + headers = factory_auth_header(jwt=jwt, claims=claims) + rv = client.put('/api/user/', headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.OK + + user_id = rv.json.get('id') + rv = client.get(f'/api/user/{user_id}', headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.OK + assert rv.json.get('id') == user_id + + +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.BAD_REQUEST), + (ValueError('Test error'), HTTPStatus.BAD_REQUEST), +]) +def test_errors_on_toggle_user_active_status(client, jwt, session, side_effect, expected_status, + setup_admin_user_and_claims): + """Assert that a user can be toggled.""" + user = factory_staff_user_model() + + assert user.status_id == UserStatus.ACTIVE.value + user, claims = setup_admin_user_and_claims + headers = factory_auth_header(jwt=jwt, claims=claims) + + with patch.object(StaffUserMembershipService, 'reactivate_deactivate_user', side_effect=side_effect): + rv = client.patch( + f'/api/user/{user.external_id}/status', + headers=headers, + json={'active': False}, + content_type=ContentType.JSON.value + ) + assert rv.status_code == expected_status diff --git a/met-api/tests/unit/api/test_user_membership.py b/met-api/tests/unit/api/test_user_membership.py index a4edd90e5..f91fb16c8 100644 --- a/met-api/tests/unit/api/test_user_membership.py +++ b/met-api/tests/unit/api/test_user_membership.py @@ -17,9 +17,12 @@ Test-Suite to ensure that the user membership endpoints are working as expected. """ from http import HTTPStatus -from unittest.mock import MagicMock +from unittest.mock import MagicMock, patch +import pytest +from met_api.exceptions.business_exception import BusinessException from met_api.models.membership import Membership as MembershipModel +from met_api.services.staff_user_membership_service import StaffUserMembershipService from met_api.utils.enums import ContentType, KeycloakGroupName, MembershipStatus, UserStatus from tests.utilities.factory_scenarios import TestJwtClaims from tests.utilities.factory_utils import ( @@ -62,7 +65,11 @@ def mock_keycloak_methods(mocker, mock_group_names): ) -def test_reassign_user_reviewer_team_member(mocker, client, jwt, session): +@pytest.mark.parametrize('side_effect, expected_status', [ + (KeyError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), + (ValueError('Test error'), HTTPStatus.INTERNAL_SERVER_ERROR), +]) +def test_reassign_user_reviewer_team_member(mocker, client, jwt, session, side_effect, expected_status): """Assert that returns bad request if bad request body.""" user = factory_staff_user_model() eng = factory_engagement_model() @@ -106,3 +113,20 @@ def test_reassign_user_reviewer_team_member(mocker, client, jwt, session): memberships = MembershipModel.find_by_user_id(user.id) assert len(memberships) == 1 assert memberships[0].status == MembershipStatus.REVOKED.value + + with patch.object(StaffUserMembershipService, 'reassign_user', side_effect=side_effect): + rv = client.put( + f'/api/user/{user.id}/groups?group=EAO_TEAM_MEMBER', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == expected_status + + with patch.object(StaffUserMembershipService, 'reassign_user', + side_effect=BusinessException('Test error', status_code=HTTPStatus.INTERNAL_SERVER_ERROR)): + rv = client.put( + f'/api/user/{user.id}/groups?group=EAO_TEAM_MEMBER', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR diff --git a/met-api/tests/unit/api/test_widget.py b/met-api/tests/unit/api/test_widget.py index 7c1b65c9e..8b16bf74a 100644 --- a/met-api/tests/unit/api/test_widget.py +++ b/met-api/tests/unit/api/test_widget.py @@ -18,11 +18,14 @@ """ import json from http import HTTPStatus +from marshmallow import ValidationError +from unittest.mock import patch import pytest from faker import Faker from met_api.constants.widget import WidgetType +from met_api.services.widget_service import WidgetService from met_api.utils.enums import ContentType from tests.utilities.factory_scenarios import TestWidgetInfo, TestWidgetItemInfo from tests.utilities.factory_utils import factory_auth_header, factory_engagement_model, factory_widget_model @@ -48,6 +51,39 @@ def test_create_widget(client, jwt, session, widget_info, assert rv.status_code == 200 assert rv.json[0].get('sort_index') == 1 + with patch.object(WidgetService, 'create_widget', side_effect=ValueError('Test error')): + rv = client.post('/api/widgets/engagement/' + str(engagement.id), data=json.dumps(widget_info), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + + with patch.object(WidgetService, 'create_widget', side_effect=ValidationError('Test error')): + rv = client.post('/api/widgets/engagement/' + str(engagement.id), data=json.dumps(widget_info), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + + +@pytest.mark.parametrize('widget_info', [TestWidgetInfo.widget1]) +def test_get_widget(client, jwt, session, widget_info, + setup_admin_user_and_claims): # pylint:disable=unused-argument + """Assert that a widget can be fetched.""" + engagement = factory_engagement_model() + widget_info['engagement_id'] = engagement.id + user, claims = setup_admin_user_and_claims + headers = factory_auth_header(jwt=jwt, claims=claims) + rv = client.post('/api/widgets/engagement/' + str(engagement.id), data=json.dumps(widget_info), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == 200 + + rv = client.get('/api/widgets/engagement/' + str(engagement.id), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == 200 + assert rv.json[0].get('sort_index') == 1 + + with patch.object(WidgetService, 'get_widgets_by_engagement_id', side_effect=ValueError('Test error')): + rv = client.get('/api/widgets/engagement/' + str(engagement.id), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + def test_create_widget_sort(client, jwt, session, setup_admin_user_and_claims): # pylint:disable=unused-argument @@ -154,6 +190,11 @@ def test_create_widget_items(client, jwt, session, widget_item_info, headers=headers, content_type=ContentType.JSON.value) assert rv.status_code == 200 + with patch.object(WidgetService, 'save_widget_items_bulk', side_effect=ValueError('Test error')): + rv = client.post('/api/widgets/' + str(widget.id) + '/items', data=json.dumps([data]), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + def test_delete_widget(client, jwt, session, setup_admin_user_and_claims): # pylint:disable=unused-argument @@ -170,6 +211,12 @@ def test_delete_widget(client, jwt, session, assert rv.status_code == HTTPStatus.OK + widget = factory_widget_model(TestWidgetInfo.widget1) + with patch.object(WidgetService, 'delete_widget', side_effect=ValueError('Test error')): + rv = client.delete(f'/api/widgets/{widget.id}/engagements/' + str(engagement.id), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + def test_patch_widget(client, jwt, session, setup_admin_user_and_claims): # pylint:disable=unused-argument @@ -189,3 +236,13 @@ def test_patch_widget(client, jwt, session, assert rv.status_code == HTTPStatus.OK assert rv.json.get('title') == data.get('title') + + with patch.object(WidgetService, 'update_widget', side_effect=ValueError('Test error')): + rv = client.patch(f'/api/widgets/{widget.id}/engagements/' + str(engagement.id), data=json.dumps(data), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + + with patch.object(WidgetService, 'update_widget', side_effect=ValidationError('Test error')): + rv = client.patch(f'/api/widgets/{widget.id}/engagements/' + str(engagement.id), data=json.dumps(data), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR diff --git a/met-api/tests/unit/api/test_widget_document.py b/met-api/tests/unit/api/test_widget_document.py index 609080240..08d612259 100644 --- a/met-api/tests/unit/api/test_widget_document.py +++ b/met-api/tests/unit/api/test_widget_document.py @@ -20,8 +20,11 @@ from http import HTTPStatus from faker import Faker +from unittest.mock import patch import pytest +from met_api.exceptions.business_exception import BusinessException +from met_api.services.widget_documents_service import WidgetDocumentService from met_api.utils.enums import ContentType, WidgetDocumentType from tests.utilities.factory_scenarios import TestJwtClaims, TestWidgetDocumentInfo, TestWidgetInfo from tests.utilities.factory_utils import ( @@ -52,6 +55,16 @@ def test_create_documents(client, jwt, session, document_info): # pylint:disabl ) assert rv.status_code == HTTPStatus.OK + with patch.object(WidgetDocumentService, 'create_document', + side_effect=BusinessException('Test error', status_code=HTTPStatus.INTERNAL_SERVER_ERROR)): + rv = client.post( + f'/api/widgets/{widget.id}/documents', + data=json.dumps(data), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + def test_get_document(client, jwt, session): # pylint:disable=unused-argument """Assert that widget items can be POSTed.""" @@ -75,6 +88,15 @@ def test_get_document(client, jwt, session): # pylint:disable=unused-argument assert rv.status_code == HTTPStatus.OK assert rv.json.get('children')[0].get('id') == document.id + with patch.object(WidgetDocumentService, 'get_documents_by_widget_id', side_effect=ValueError('Test error')): + rv = client.get( + f'/api/widgets/{widget.id}/documents', + headers=headers, + content_type=ContentType.JSON.value + ) + + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + def test_assert_tree_structure_invalid(client, jwt, session): # pylint:disable=unused-argument """Assert that widget items can be POSTed.""" @@ -98,7 +120,7 @@ def test_assert_tree_structure_invalid(client, jwt, session): # pylint:disable= content_type=ContentType.JSON.value ) # TODO once we remove action result , this should be HTTP 400 - assert rv.status_code == 500 + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR def test_assert_tree_structure(client, jwt, session): # pylint:disable=unused-argument @@ -163,6 +185,13 @@ def test_patch_documents(client, jwt, session): # pylint:disable=unused-argumen assert rv.status_code == HTTPStatus.OK assert rv.json.get('children')[0].get('title') == document_edits.get('title') + with patch.object(WidgetDocumentService, 'edit_document', + side_effect=BusinessException('Test error', status_code=HTTPStatus.INTERNAL_SERVER_ERROR)): + rv = client.patch(f'/api/widgets/{widget.id}/documents/{document.id}', + data=json.dumps(document_edits), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + def test_delete_documents(client, jwt, session): # pylint:disable=unused-argument """Assert that a document can be PATCHed.""" @@ -178,6 +207,12 @@ def test_delete_documents(client, jwt, session): # pylint:disable=unused-argume assert rv.status_code == HTTPStatus.OK + document = factory_document_model(TestWidgetDocumentInfo.document1) + with patch.object(WidgetDocumentService, 'delete_document', side_effect=ValueError('Test error')): + rv = client.delete(f'/api/widgets/{widget.id}/documents/{document.id}', + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + def test_sort_folders(client, jwt, session): """Test sorting of folders.""" @@ -244,6 +279,13 @@ def test_sort_folders(client, jwt, session): reset_order = [doc['id'] for doc in rv.json['children'] if doc.get('type') == 'folder'] assert reset_order == initial_order + with patch.object(WidgetDocumentService, 'sort_documents', + side_effect=BusinessException('Test error', status_code=HTTPStatus.INTERNAL_SERVER_ERROR)): + rv = client.patch(f'/api/widgets/{widget.id}/documents/order', data=json.dumps({ + 'documents': reset_reorder_dict}), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.INTERNAL_SERVER_ERROR + def test_sort_files(client, jwt, session): """Test sorting of documents within a folder.""" diff --git a/met-api/tests/unit/api/test_widget_event.py b/met-api/tests/unit/api/test_widget_event.py index 5b578fa1f..d7ac4b3e5 100644 --- a/met-api/tests/unit/api/test_widget_event.py +++ b/met-api/tests/unit/api/test_widget_event.py @@ -18,10 +18,14 @@ """ import json +from http import HTTPStatus from faker import Faker +from unittest.mock import patch from met_api.utils.enums import ContentType from met_api.constants.event_types import EventTypes +from met_api.exceptions.business_exception import BusinessException +from met_api.services.widget_events_service import WidgetEventsService from tests.utilities.factory_scenarios import TestEventnfo, TestJwtClaims, TestWidgetInfo from tests.utilities.factory_utils import factory_auth_header, factory_engagement_model, factory_widget_model @@ -48,12 +52,22 @@ def test_create_events(client, jwt, session): # pylint:disable=unused-argument headers=headers, content_type=ContentType.JSON.value ) - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value assert rv.json.get('title') == event_info.get('title') response_event_items = rv.json.get('event_items') assert len(response_event_items) == 1 assert response_event_items[0].get('description') == event_info.get('items')[0].get('description') + with patch.object(WidgetEventsService, 'create_event', + side_effect=BusinessException('Test error', status_code=HTTPStatus.BAD_REQUEST)): + rv = client.post( + f'/api/widgets/{widget.id}/events', + data=json.dumps(data), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.BAD_REQUEST + def test_widget_events_sort(client, jwt, session): # pylint:disable=unused-argument """Assert that a widget events can be sorted.""" @@ -73,7 +87,7 @@ def test_widget_events_sort(client, jwt, session): # pylint:disable=unused-argu headers=headers, content_type=ContentType.JSON.value ) - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value event_info = TestEventnfo.event_virtual headers = factory_auth_header(jwt=jwt, claims=TestJwtClaims.no_role) @@ -87,14 +101,14 @@ def test_widget_events_sort(client, jwt, session): # pylint:disable=unused-argu headers=headers, content_type=ContentType.JSON.value ) - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value rv = client.get( f'/api/widgets/{widget.id}/events', headers=headers, content_type=ContentType.JSON.value ) - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value assert len(rv.json) == 2, 'Two Widget Events Should exist.' widget_events = rv.json open_house_event = _find_widget_events(widget_events, EventTypes.OPENHOUSE) @@ -119,7 +133,7 @@ def test_widget_events_sort(client, jwt, session): # pylint:disable=unused-argu headers=headers, content_type=ContentType.JSON.value ) - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value rv = client.get( f'/api/widgets/{widget.id}/events', @@ -133,7 +147,116 @@ def test_widget_events_sort(client, jwt, session): # pylint:disable=unused-argu virtual_event = _find_widget_events(widget_events, EventTypes.VIRTUAL) assert virtual_event.get('sort_index') == 1 + with patch.object(WidgetEventsService, 'save_widget_events_bulk', + side_effect=BusinessException('Test error', status_code=HTTPStatus.BAD_REQUEST)): + rv = client.patch( + f'/api/widgets/{widget.id}/events/sort_index', + data=json.dumps(reorder_dict), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.BAD_REQUEST + def _find_widget_events(widget_events, widget_event_type): _widget_event_type = next(x for x in widget_events if x.get('type') == widget_event_type.name) return _widget_event_type + + +def test_delete_events(client, jwt, session): # pylint:disable=unused-argument + """Assert that widget events can be deleted.""" + engagement = factory_engagement_model() + TestWidgetInfo.widget1['engagement_id'] = engagement.id + widget = factory_widget_model(TestWidgetInfo.widget1) + event_info = TestEventnfo.event_meetup + headers = factory_auth_header(jwt=jwt, claims=TestJwtClaims.no_role) + + data = { + **event_info, + 'widget_id': widget.id, + } + + rv = client.post( + f'/api/widgets/{widget.id}/events', + data=json.dumps(data), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.OK.value + + event_id = rv.json.get('id') + rv = client.delete( + f'/api/widgets/{widget.id}/events/{event_id}', + data=json.dumps(data), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.OK.value + + with patch.object(WidgetEventsService, 'delete_event', + side_effect=BusinessException('Test error', status_code=HTTPStatus.BAD_REQUEST)): + rv = client.delete( + f'/api/widgets/{widget.id}/events/{event_id}', + data=json.dumps(data), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.BAD_REQUEST + + +def test_patch_events(client, jwt, session): # pylint:disable=unused-argument + """Assert that widget events can be PATCHed.""" + engagement = factory_engagement_model() + TestWidgetInfo.widget1['engagement_id'] = engagement.id + widget = factory_widget_model(TestWidgetInfo.widget1) + event_info = TestEventnfo.event_meetup + headers = factory_auth_header(jwt=jwt, claims=TestJwtClaims.no_role) + + data = { + **event_info, + 'widget_id': widget.id, + } + + rv = client.post( + f'/api/widgets/{widget.id}/events', + data=json.dumps(data), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.OK.value + response_event_items = rv.json.get('event_items') + item_id = response_event_items[0].get('id') + event_id = rv.json.get('id') + + event_edits = { + 'description': fake.text(max_nb_chars=20), + 'start_date': fake.date() + } + + rv = client.patch( + f'/api/widgets/{widget.id}/events/{event_id}/item/{item_id}', + data=json.dumps(event_edits), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.OK.value + + rv = client.get( + f'/api/widgets/{widget.id}/events', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.OK.value + event_items = rv.json[0].get('event_items', []) + description_value = event_items[0].get('description') + assert description_value == event_edits.get('description') + + with patch.object(WidgetEventsService, 'update_event_item', + side_effect=BusinessException('Test error', status_code=HTTPStatus.BAD_REQUEST)): + rv = client.patch( + f'/api/widgets/{widget.id}/events/{event_id}/item/{item_id}', + data=json.dumps(event_edits), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.BAD_REQUEST diff --git a/met-api/tests/unit/api/test_widget_map.py b/met-api/tests/unit/api/test_widget_map.py index 4d5080dbc..59e085149 100644 --- a/met-api/tests/unit/api/test_widget_map.py +++ b/met-api/tests/unit/api/test_widget_map.py @@ -17,10 +17,14 @@ Test-Suite to ensure that the Widget Map API endpoint is working as expected. """ +import json from http import HTTPStatus from faker import Faker +from unittest.mock import patch +from met_api.exceptions.business_exception import BusinessException +from met_api.services.widget_map_service import WidgetMapService from met_api.utils.enums import ContentType from tests.utilities.factory_scenarios import TestJwtClaims, TestWidgetInfo, TestWidgetMap from tests.utilities.factory_utils import ( @@ -57,6 +61,16 @@ def test_create_map_widget(client, jwt, session, assert rv.status_code == HTTPStatus.OK.value assert float(rv.json.get('longitude')) == float(map_info.get('longitude')) + with patch.object(WidgetMapService, 'create_map', + side_effect=BusinessException('Test error', status_code=HTTPStatus.BAD_REQUEST)): + rv = client.post( + f'/api/widgets/{widget.id}/maps', + data=data, + headers=headers, + content_type=ContentType.FORM.value + ) + assert rv.status_code == HTTPStatus.BAD_REQUEST + def test_get_map(client, jwt, session): # pylint:disable=unused-argument """Assert that map can be fetched.""" @@ -84,3 +98,64 @@ def test_get_map(client, jwt, session): # pylint:disable=unused-argument assert rv.status_code == HTTPStatus.OK assert rv.json[0].get('id') == widget_map.id + + with patch.object(WidgetMapService, 'get_map', + side_effect=BusinessException('Test error', status_code=HTTPStatus.BAD_REQUEST)): + rv = client.get( + f'/api/widgets/{widget.id}/maps', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.BAD_REQUEST + + +def test_patch_map(client, jwt, session, + setup_admin_user_and_claims): # pylint:disable=unused-argument + """Assert that map can be PATCHed.""" + user, claims = setup_admin_user_and_claims + engagement = factory_engagement_model() + TestWidgetInfo.widget_map['engagement_id'] = engagement.id + widget = factory_widget_model(TestWidgetInfo.widget_map) + + headers = factory_auth_header(jwt=jwt, claims=claims) + + map_widget_info = TestWidgetMap.map1 + + factory_widget_map_model({ + 'widget_id': widget.id, + 'engagement_id': engagement.id, + 'longitude': map_widget_info.get('longitude'), + 'latitude': map_widget_info.get('latitude'), + 'marker_label': map_widget_info.get('marker_label'), + }) + + map_edits = { + 'longitude': str(fake.longitude()) + } + + rv = client.patch( + f'/api/widgets/{widget.id}/maps', + data=json.dumps(map_edits), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.OK + + rv = client.get( + f'/api/widgets/{widget.id}/maps', + headers=headers, + content_type=ContentType.JSON.value + ) + + assert rv.status_code == HTTPStatus.OK + assert round(float(rv.json[0].get('longitude')), 5) == round(float(map_edits.get('longitude')), 5) + + with patch.object(WidgetMapService, 'update_map', + side_effect=BusinessException('Test error', status_code=HTTPStatus.BAD_REQUEST)): + rv = client.patch( + f'/api/widgets/{widget.id}/maps', + data=json.dumps(map_edits), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.BAD_REQUEST diff --git a/met-api/tests/unit/api/test_widget_subscribe.py b/met-api/tests/unit/api/test_widget_subscribe.py index 9c4ab9018..4a2d32f9c 100644 --- a/met-api/tests/unit/api/test_widget_subscribe.py +++ b/met-api/tests/unit/api/test_widget_subscribe.py @@ -19,8 +19,13 @@ """ import json +from http import HTTPStatus from faker import Faker +from unittest.mock import patch +from met_api.constants.subscribe_types import SubscribeTypes +from met_api.exceptions.business_exception import BusinessException +from met_api.services.widget_subscribe_service import WidgetSubscribeService from met_api.utils.enums import ContentType from tests.utilities.factory_scenarios import TestJwtClaims, TestSubscribeInfo, TestWidgetInfo from tests.utilities.factory_utils import factory_auth_header, factory_engagement_model, factory_widget_model @@ -54,9 +59,24 @@ def test_create_subscribe(client, jwt, session): # pylint:disable=unused-argume content_type=ContentType.JSON.value, ) # Checking response - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value assert rv.json.get('type') == subscribe_info.get('type') - # ... + + # test create subscribe exception + data = { + **subscribe_info, + 'widget_id': fake.pyint(), + } + + with patch.object(WidgetSubscribeService, 'create_subscribe', + side_effect=BusinessException('Test error', status_code=HTTPStatus.BAD_REQUEST)): + rv = client.post( + f'/api/widgets/{widget.id}/subscribe', + data=json.dumps(data), + headers=headers, + content_type=ContentType.JSON.value, + ) + assert rv.status_code == HTTPStatus.BAD_REQUEST def test_get_subscribe(client, jwt, session): # pylint:disable=unused-argument @@ -85,7 +105,7 @@ def test_get_subscribe(client, jwt, session): # pylint:disable=unused-argument ) # Checking POST response - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value # Sending GET request rv = client.get( @@ -95,5 +115,182 @@ def test_get_subscribe(client, jwt, session): # pylint:disable=unused-argument ) # Checking GET response - assert rv.status_code == 200 + assert rv.status_code == HTTPStatus.OK.value assert rv.json[0].get('type') == subscribe_info.get('type') + + +def test_delete_subscribe(client, jwt, session): # pylint:disable=unused-argument + """Assert that widget subscribe can be deleted.""" + engagement = factory_engagement_model() + + TestWidgetInfo.widget1['engagement_id'] = engagement.id + widget = factory_widget_model(TestWidgetInfo.widget1) + + subscribe_info = TestSubscribeInfo.subscribe_info_1.value + + headers = factory_auth_header(jwt=jwt, claims=TestJwtClaims.no_role) + + # Preparing data + data = { + **subscribe_info, + 'widget_id': widget.id, + } + + # Sending POST request + rv = client.post( + f'/api/widgets/{widget.id}/subscribe', + data=json.dumps(data), + headers=headers, + content_type=ContentType.JSON.value, + ) + # Checking response + assert rv.status_code == HTTPStatus.OK.value + subscribe_id = rv.json.get('id') + + # Sending DELETE request + rv = client.delete( + f'/api/widgets/{widget.id}/subscribe/{subscribe_id}', + headers=headers, + content_type=ContentType.JSON.value, + ) + # Checking response + assert rv.status_code == HTTPStatus.OK.value + + # test delete subscribe exception + widget_id = fake.pyint() + # Sending DELETE request + with patch.object(WidgetSubscribeService, 'delete_subscribe', + side_effect=BusinessException('Test error', status_code=HTTPStatus.BAD_REQUEST)): + rv = client.delete( + f'/api/widgets/{widget_id}/subscribe/{subscribe_id}', + headers=headers, + content_type=ContentType.JSON.value, + ) + # Checking response + assert rv.status_code == HTTPStatus.BAD_REQUEST + + +def test_subscribe_sorting(client, jwt, session): # pylint:disable=unused-argument + """Assert that widget subscribe can be sorted.""" + engagement = factory_engagement_model() + + TestWidgetInfo.widget1['engagement_id'] = engagement.id + widget = factory_widget_model(TestWidgetInfo.widget1) + headers = factory_auth_header(jwt=jwt, claims=TestJwtClaims.no_role) + + subscribe_info = TestSubscribeInfo.subscribe_info_1.value + data = { + **subscribe_info, + 'widget_id': widget.id, + } + rv = client.post(f'/api/widgets/{widget.id}/subscribe', data=json.dumps(data), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.OK.value + + subscribe_info = TestSubscribeInfo.subscribe_info_2.value + data = { + **subscribe_info, + 'widget_id': widget.id, + } + rv = client.post(f'/api/widgets/{widget.id}/subscribe', data=json.dumps(data), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.OK.value + + rv = client.get(f'/api/widgets/{widget.id}/subscribe', headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.OK.value + assert len(rv.json) == 2, 'Two Items Should exist.' + widgets = rv.json + email_list = _find_item(widgets, SubscribeTypes.EMAIL_LIST.name) + assert email_list.get('sort_index') == 1 + + sign_up = _find_item(widgets, SubscribeTypes.SIGN_UP.name) + assert sign_up.get('sort_index') == 2 + + # Do reorder + reorder_dict = [ + { + 'id': sign_up.get('id'), + }, + { + 'id': email_list.get('id'), + } + ] + + rv = client.patch(f'/api/widgets/{widget.id}/subscribe/sort_index', data=json.dumps(reorder_dict), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.OK.value + + rv = client.get(f'/api/widgets/{widget.id}/subscribe', headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.OK.value + widgets = rv.json + email_list = _find_item(widgets, SubscribeTypes.EMAIL_LIST.name) + assert email_list.get('sort_index') == 2 + + sign_up = _find_item(widgets, SubscribeTypes.SIGN_UP.name) + assert sign_up.get('sort_index') == 1 + + # test subscribe sorting exception + widget_id = fake.pyint() + with patch.object(WidgetSubscribeService, 'save_widget_subscribes_bulk', + side_effect=BusinessException('Test error', status_code=HTTPStatus.BAD_REQUEST)): + rv = client.patch(f'/api/widgets/{widget_id}/subscribe/sort_index', data=json.dumps(reorder_dict), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.BAD_REQUEST + + +def _find_item(widgets, type): + widget_type = next(x for x in widgets if x.get('type') == type) + return widget_type + + +def test_update_subscribe(client, jwt, session): # pylint:disable=unused-argument + """Assert that widget subscribe can be PATCHed.""" + engagement = factory_engagement_model() + + TestWidgetInfo.widget1['engagement_id'] = engagement.id + widget = factory_widget_model(TestWidgetInfo.widget1) + + subscribe_info = TestSubscribeInfo.subscribe_info_1.value + + headers = factory_auth_header(jwt=jwt, claims=TestJwtClaims.no_role) + + # Preparing data + data = { + **subscribe_info, + 'widget_id': widget.id, + } + # Sending POST request + rv = client.post( + f'/api/widgets/{widget.id}/subscribe', + data=json.dumps(data), + headers=headers, + content_type=ContentType.JSON.value, + ) + # Checking response + assert rv.status_code == HTTPStatus.OK.value + subscribe_id = rv.json.get('id') + subscribe_items = rv.json.get('subscribe_items') + item_id = subscribe_items[0].get('id') + + subscribe_edits = { + 'description': fake.text(max_nb_chars=20), + 'call_to_action_text': fake.text(max_nb_chars=20) + } + # Sending PATCH request + rv = client.patch(f'/api/widgets/{widget.id}/subscribe/{subscribe_id}/item/{item_id}', + data=json.dumps(subscribe_edits), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.OK + + rv = client.get(f'/api/widgets/{widget.id}/subscribe', headers=headers, content_type=ContentType.JSON.value) + subscribe_items = rv.json[0].get('subscribe_items') + assert subscribe_items[0].get('call_to_action_text') == subscribe_edits.get('call_to_action_text') + + # test update subscribe exception + widget_id = fake.pyint() + with patch.object(WidgetSubscribeService, 'update_subscribe_item', + side_effect=BusinessException('Test error', status_code=HTTPStatus.BAD_REQUEST)): + rv = client.patch(f'/api/widgets/{widget_id}/subscribe/{subscribe_id}/item/{item_id}', + data=json.dumps(subscribe_edits), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.BAD_REQUEST diff --git a/met-api/tests/unit/api/test_widget_timeline.py b/met-api/tests/unit/api/test_widget_timeline.py index 143565fe8..3b7e7308a 100644 --- a/met-api/tests/unit/api/test_widget_timeline.py +++ b/met-api/tests/unit/api/test_widget_timeline.py @@ -19,10 +19,13 @@ """ import json from http import HTTPStatus +from unittest.mock import patch from faker import Faker from met_api.constants.timeline_event_status import TimelineEventStatus +from met_api.exceptions.business_exception import BusinessException +from met_api.services.widget_timeline_service import WidgetTimelineService from met_api.utils.enums import ContentType from tests.utilities.factory_scenarios import TestJwtClaims, TestTimelineInfo, TestWidgetInfo from tests.utilities.factory_utils import ( @@ -67,6 +70,16 @@ def test_create_timeline_widget(client, jwt, session, assert rv.status_code == HTTPStatus.OK.value assert rv.json.get('engagement_id') == engagement.id + with patch.object(WidgetTimelineService, 'create_timeline', + side_effect=BusinessException('Test error', status_code=HTTPStatus.BAD_REQUEST)): + rv = client.post( + f'/api/widgets/{widget.id}/timelines', + data=json.dumps(data), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.BAD_REQUEST + def test_get_timeline(client, jwt, session): # pylint:disable=unused-argument """Assert that timeline can be fetched.""" @@ -106,6 +119,15 @@ def test_get_timeline(client, jwt, session): # pylint:disable=unused-argument assert rv.json[0].get('id') == widget_timeline.id assert len(rv.json[0]['events']) == 1 + with patch.object(WidgetTimelineService, 'get_timeline', + side_effect=BusinessException('Test error', status_code=HTTPStatus.BAD_REQUEST)): + rv = client.get( + f'/api/widgets/{widget.id}/timelines', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.BAD_REQUEST + def test_patch_timeline(client, jwt, session, setup_admin_user_and_claims): # pylint:disable=unused-argument @@ -165,3 +187,10 @@ def test_patch_timeline(client, jwt, session, assert rv.status_code == HTTPStatus.OK assert rv.json[0].get('description') == timeline_edits.get('description') assert len(rv.json[0]['events']) == 1 + + with patch.object(WidgetTimelineService, 'update_timeline', + side_effect=BusinessException('Test error', status_code=HTTPStatus.BAD_REQUEST)): + rv = client.patch(f'/api/widgets/{widget.id}/timelines/{timeline_event.id}', + data=json.dumps(timeline_edits), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.BAD_REQUEST diff --git a/met-api/tests/unit/api/test_widget_video.py b/met-api/tests/unit/api/test_widget_video.py index bf314b0bd..d2c6aa10e 100644 --- a/met-api/tests/unit/api/test_widget_video.py +++ b/met-api/tests/unit/api/test_widget_video.py @@ -19,10 +19,13 @@ """ import json from http import HTTPStatus +from unittest.mock import patch from faker import Faker from met_api.utils.enums import ContentType +from met_api.exceptions.business_exception import BusinessException +from met_api.services.widget_video_service import WidgetVideoService from tests.utilities.factory_scenarios import TestJwtClaims, TestWidgetInfo, TestWidgetVideo from tests.utilities.factory_utils import ( factory_auth_header, factory_engagement_model, factory_video_model, factory_widget_model) @@ -56,6 +59,16 @@ def test_create_video_widget(client, jwt, session, assert rv.status_code == HTTPStatus.OK.value assert rv.json.get('video_url') == video_info.get('video_url') + with patch.object(WidgetVideoService, 'create_video', + side_effect=BusinessException('Test error', status_code=HTTPStatus.BAD_REQUEST)): + rv = client.post( + f'/api/widgets/{widget.id}/videos', + data=json.dumps(data), + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.BAD_REQUEST + def test_get_video(client, jwt, session): # pylint:disable=unused-argument """Assert that video can be fetched.""" @@ -80,6 +93,15 @@ def test_get_video(client, jwt, session): # pylint:disable=unused-argument assert rv.status_code == HTTPStatus.OK assert rv.json[0].get('id') == video.id + with patch.object(WidgetVideoService, 'get_video', + side_effect=BusinessException('Test error', status_code=HTTPStatus.BAD_REQUEST)): + rv = client.get( + f'/api/widgets/{widget.id}/videos', + headers=headers, + content_type=ContentType.JSON.value + ) + assert rv.status_code == HTTPStatus.BAD_REQUEST + def test_patch_video(client, jwt, session, setup_admin_user_and_claims): # pylint:disable=unused-argument @@ -115,3 +137,10 @@ def test_patch_video(client, jwt, session, ) assert rv.status_code == HTTPStatus.OK assert rv.json[0].get('description') == video_edits.get('description') + + with patch.object(WidgetVideoService, 'update_video', + side_effect=BusinessException('Test error', status_code=HTTPStatus.BAD_REQUEST)): + rv = client.patch(f'/api/widgets/{widget.id}/videos/{video.id}', + data=json.dumps(video_edits), + headers=headers, content_type=ContentType.JSON.value) + assert rv.status_code == HTTPStatus.BAD_REQUEST diff --git a/met-api/tests/utilities/factory_scenarios.py b/met-api/tests/utilities/factory_scenarios.py index ab2d896f5..4b15ca5a7 100644 --- a/met-api/tests/utilities/factory_scenarios.py +++ b/met-api/tests/utilities/factory_scenarios.py @@ -346,7 +346,8 @@ class TestJwtClaims(dict, Enum): 'update_user_group', 'export_proponent_comment_sheet', 'export_internal_comment_sheet', - 'export_cac_form_to_sheet' + 'export_cac_form_to_sheet', + 'view_members' ] } team_member_role = {