"""Test the PATCH /v2/identities endpoint.""" import pytest import requests from tests.integration import config, utils subaccount_base_roles = [ 'INSIGHTS_BASE_ROLE', 'CUSTOMER_ACCOUNTING_BASE_ROLE', 'WORKSTATION_CATALOG_ROLE', ] @pytest.mark.parametrize( ( 'roles_to_attach', 'roles_to_detach', 'expected_label_profile_roles', 'additional_creation_roles', ), [ # Both SETTINGS_BASE_ROLE + WORKSTATION_ADMIN_ROLE, detaching # COLLABORATORS_BASE_ROLE, WORKSTATION_ANALYTICS_BASE_ROLE pytest.param( ['SETTINGS_BASE_ROLE', 'WORKSTATION_ADMIN_ROLE'], ['COLLABORATORS_BASE_ROLE', 'WORKSTATION_ANALYTICS_BASE_ROLE'], ['marketing', 'administrator', 'catalog', 'advertising'], [], id='both_settings_and_workstation_admin_with_detach', ), # Only SETTINGS_BASE_ROLE, detaching COLLABORATORS_BASE_ROLE pytest.param( ['SETTINGS_BASE_ROLE'], ['COLLABORATORS_BASE_ROLE'], ['analytics', 'marketing', 'catalog', 'advertising'], [], id='only_settings_with_detach', ), # Only WORKSTATION_ADMIN_ROLE, detaching COLLABORATORS_BASE_ROLE, WORKSTATION_CATALOG_ROLE pytest.param( ['WORKSTATION_ADMIN_ROLE'], ['COLLABORATORS_BASE_ROLE', 'WORKSTATION_CATALOG_ROLE'], ['marketing', 'administrator', 'advertising', 'analytics'], [], id='only_workstation_admin_with_detach', ), # create user with both admin roles and then detach both admin roles pytest.param( [], ['SETTINGS_BASE_ROLE', 'WORKSTATION_ADMIN_ROLE'], ['marketing', 'catalog', 'advertising', 'analytics'], ['SETTINGS_BASE_ROLE', 'WORKSTATION_ADMIN_ROLE'], id='detach_both_admin_roles', ), ], ) def test_update_identity_v2_account( bearer_token_user_with_vendor_star: str, create_identity_json: dict, roles_to_attach: list[str], roles_to_detach: list[str], expected_label_profile_roles: list[str], additional_creation_roles: list[str], ) -> None: """Integration test for update_identity_v2 endpoint with account tenant.""" # set final roles after attach/detach operations initial_roles = create_identity_json['roles_to_attach'] + additional_creation_roles final_roles = [role for role in initial_roles if role not in roles_to_detach] + roles_to_attach response = requests.post( f'{config.QA_BASE_URL}/v2/identities', json={ **create_identity_json, 'roles_to_attach': create_identity_json['roles_to_attach'] + additional_creation_roles, }, headers={ 'Authorization': f'Bearer {bearer_token_user_with_vendor_star}', 'Orchard-Profile-Type': 'SettingsProfile', 'Orchard-Profile-Id': utils.OWS_ACCOUNT_TEST_USER_SETTINGS_PROFILE_ID, 'Orchard-Identity-Id': utils.OWS_ACCOUNT_TEST_USER_ID, }, ) assert response.status_code == 200, response.text identity_id = response.json()['id'] # Update identity by attaching and detaching roles update_body = { 'roles_to_attach': roles_to_attach, 'roles_to_detach': roles_to_detach, 'tenant': { 'tenant_type': create_identity_json['tenant']['tenant_type'], 'tenant_uuid': create_identity_json['tenant']['tenant_uuid'], }, } res = requests.patch( f'{config.QA_BASE_URL}/v2/identities/{identity_id}', json=update_body, headers={ 'Authorization': f'Bearer {bearer_token_user_with_vendor_star}', 'Orchard-Profile-Type': 'SettingsProfile', 'Orchard-Profile-Id': utils.OWS_ACCOUNT_TEST_USER_SETTINGS_PROFILE_ID, 'Orchard-Identity-Id': utils.OWS_ACCOUNT_TEST_USER_ID, }, ) assert res.status_code == 200, res.text body = res.json() assert body['id'] == identity_id # GET tenants by identity_id to verify that identity has the correct roles res = requests.get( f'{config.QA_BASE_URL}/v2/identity/{identity_id}/tenants', headers={ 'Authorization': f'Bearer {bearer_token_user_with_vendor_star}', 'Orchard-Profile-Type': 'SettingsProfile', 'Orchard-Profile-Id': utils.OWS_ACCOUNT_TEST_USER_SETTINGS_PROFILE_ID, 'Orchard-Identity-Id': utils.OWS_ACCOUNT_TEST_USER_ID, }, ) assert res.status_code == 200, res.text tenants = res.json()['tenants'] assert tenants[0]['tenant_uuid'] == create_identity_json['tenant']['tenant_uuid'] assert tenants[0]['tenant_type'] == create_identity_json['tenant']['tenant_type'] assert set(tenants[0]['roles']) == set(final_roles) @pytest.mark.parametrize( ( 'roles_to_attach', 'roles_to_detach', 'expected_label_profile_roles', 'additional_creation_roles', ), [ # Both SETTINGS_BASE_ROLE + WORKSTATION_ADMIN_ROLE, detaching # CUSTOMER_ACCOUNTING_BASE_ROLE, WORKSTATION_CATALOG_ROLE pytest.param( ['SETTINGS_BASE_ROLE', 'WORKSTATION_ADMIN_ROLE'], ['CUSTOMER_ACCOUNTING_BASE_ROLE', 'WORKSTATION_CATALOG_ROLE'], ['administrator'], [], id='both_settings_and_workstation_admin_with_detach', ), # Only SETTINGS_BASE_ROLE, detaching CUSTOMER_ACCOUNTING_BASE_ROLE, WORKSTATION_CATALOG_ROLE pytest.param( ['SETTINGS_BASE_ROLE'], ['CUSTOMER_ACCOUNTING_BASE_ROLE', 'WORKSTATION_CATALOG_ROLE'], [], [], id='only_settings_with_detach', ), # Only WORKSTATION_ADMIN_ROLE, detaching CUSTOMER_ACCOUNTING_BASE_ROLE pytest.param( ['WORKSTATION_ADMIN_ROLE'], ['CUSTOMER_ACCOUNTING_BASE_ROLE'], ['administrator', 'catalog'], [], id='only_workstation_admin_with_detach', ), # create user with both admin roles and then detach both admin roles pytest.param( [], ['SETTINGS_BASE_ROLE', 'WORKSTATION_ADMIN_ROLE'], ['catalog'], ['SETTINGS_BASE_ROLE', 'WORKSTATION_ADMIN_ROLE'], id='detach_both_admin_roles', ), ], ) def test_update_identity_v2_subaccount( bearer_token_user_with_vendor_star: str, create_identity_with_subaccount: dict, roles_to_attach: list[str], roles_to_detach: list[str], expected_label_profile_roles: list[str], additional_creation_roles: list[str], ) -> None: """Integration test for update_identity_v2 endpoint with subaccount tenant.""" # set final roles after attach/detach operations initial_roles = create_identity_with_subaccount['roles_to_attach'] + additional_creation_roles final_roles = [role for role in initial_roles if role not in roles_to_detach] + roles_to_attach attach_deez = create_identity_with_subaccount['roles_to_attach'] + additional_creation_roles response = requests.post( f'{config.QA_BASE_URL}/v2/identities', json={**create_identity_with_subaccount, 'roles_to_attach': attach_deez}, headers={ 'Authorization': f'Bearer {bearer_token_user_with_vendor_star}', 'Orchard-Profile-Type': 'SettingsProfile', 'Orchard-Profile-Id': utils.OWS_ACCOUNT_TEST_USER_SETTINGS_PROFILE_ID, 'Orchard-Identity-Id': utils.OWS_ACCOUNT_TEST_USER_ID, }, ) assert response.status_code == 200, response.text identity_id = response.json()['id'] # Update identity by attaching and detaching roles update_body = { 'roles_to_attach': roles_to_attach, 'roles_to_detach': roles_to_detach, 'tenant': { 'tenant_type': create_identity_with_subaccount['tenant']['tenant_type'], 'tenant_uuid': create_identity_with_subaccount['tenant']['tenant_uuid'], }, } res = requests.patch( f'{config.QA_BASE_URL}/v2/identities/{identity_id}', json=update_body, headers={ 'Authorization': f'Bearer {bearer_token_user_with_vendor_star}', 'Orchard-Profile-Type': 'SettingsProfile', 'Orchard-Profile-Id': utils.OWS_ACCOUNT_TEST_USER_SETTINGS_PROFILE_ID, 'Orchard-Identity-Id': utils.OWS_ACCOUNT_TEST_USER_ID, }, ) assert res.status_code == 200, res.text body = res.json() assert body['id'] == identity_id # GET tenants by identity_id to verify that identity has the correct roles res = requests.get( f'{config.QA_BASE_URL}/v2/identity/{identity_id}/tenants', headers={ 'Authorization': f'Bearer {bearer_token_user_with_vendor_star}', 'Orchard-Profile-Type': 'SettingsProfile', 'Orchard-Profile-Id': utils.OWS_ACCOUNT_TEST_USER_SETTINGS_PROFILE_ID, 'Orchard-Identity-Id': utils.OWS_ACCOUNT_TEST_USER_ID, }, ) assert res.status_code == 200, res.text tenants = res.json()['tenants'] assert tenants[0]['tenant_uuid'] == create_identity_with_subaccount['tenant']['tenant_uuid'] assert tenants[0]['tenant_type'] == create_identity_with_subaccount['tenant']['tenant_type'] assert set(tenants[0]['roles']) == set(final_roles) @pytest.mark.parametrize( ('roles_to_attach', 'expected_status_code'), [ pytest.param(['fansifter_can_view_fan_data'], 200, id='fansifter'), pytest.param(['songwhip_read'], 200, id='songwhip'), ], ) def test_update_identity_succeeds_for_account_tenant( bearer_token_user_with_vendor_star: str, create_identity_json: dict, roles_to_attach: list[str], expected_status_code: int, ) -> None: # create identity that will be updated response = requests.post( f'{config.QA_BASE_URL}/v2/identities', json=create_identity_json, headers={ 'Authorization': f'Bearer {bearer_token_user_with_vendor_star}', 'Orchard-Profile-Type': 'SettingsProfile', 'Orchard-Profile-Id': utils.OWS_ACCOUNT_TEST_USER_SETTINGS_PROFILE_ID, 'Orchard-Identity-Id': utils.OWS_ACCOUNT_TEST_USER_ID, }, ) assert response.status_code == 200, response.text identity_id = response.json()['id'] # Update identity by setting other roles body = { 'roles_to_attach': roles_to_attach, 'roles_to_detach': [], 'tenant': {'tenant_type': 'account', 'tenant_uuid': '573d0372-7f2f-48a6-8deb-c9a6558f9549'}, } res = requests.patch( f'{config.QA_BASE_URL}/v2/identities/{identity_id}', json=body, headers={ 'Authorization': f'Bearer {bearer_token_user_with_vendor_star}', 'Orchard-Profile-Type': 'SettingsProfile', 'Orchard-Profile-Id': utils.OWS_ACCOUNT_TEST_USER_SETTINGS_PROFILE_ID, 'Orchard-Identity-Id': utils.OWS_ACCOUNT_TEST_USER_ID, }, ) assert res.status_code == expected_status_code, res.text @pytest.mark.parametrize( ('roles_to_attach', 'roles_to_detach', 'expected_status_code'), [ pytest.param( ['fansifter_can_view_fan_data'], [ 'BANKING_TAX_BASE_ROLE', 'COLLABORATORS_BASE_ROLE', 'WORKSTATION_MARKETING_ROLE', 'WORKSTATION_CATALOG_ROLE', ], 422, id='Invalid role fansifter to attach.', ), pytest.param( ['songwhip_read'], [ 'BANKING_TAX_BASE_ROLE', 'COLLABORATORS_BASE_ROLE', 'WORKSTATION_MARKETING_ROLE', 'WORKSTATION_CATALOG_ROLE', ], 422, id='Invalid role songwhip to attach.', ), pytest.param( [ 'BANKING_TAX_BASE_ROLE', 'COLLABORATORS_BASE_ROLE', 'WORKSTATION_MARKETING_ROLE', 'WORKSTATION_CATALOG_ROLE', ], ['fansifter_can_view_fan_data'], 200, id='No validation on detach.', ), pytest.param( [ 'BANKING_TAX_BASE_ROLE', 'COLLABORATORS_BASE_ROLE', 'WORKSTATION_MARKETING_ROLE', 'WORKSTATION_CATALOG_ROLE', ], ['NONEXISTENT_ROLE'], 200, id='No validation of membership in role list on detach.', ), ], ) def test_update_identity_fails_invalid_roles( bearer_token_user_with_vendor_star: str, create_identity_json: dict, roles_to_attach: list[str], roles_to_detach: list[str], expected_status_code: int, ) -> None: """Test fails to update identity with vendor star for invalid roles passed.""" # create identity that will be updated response = requests.post( f'{config.QA_BASE_URL}/v2/identities', json=create_identity_json, headers={ 'Authorization': f'Bearer {bearer_token_user_with_vendor_star}', 'Orchard-Profile-Type': 'SettingsProfile', 'Orchard-Profile-Id': utils.OWS_ACCOUNT_TEST_USER_SETTINGS_PROFILE_ID, 'Orchard-Identity-Id': utils.OWS_ACCOUNT_TEST_USER_ID, }, ) assert response.status_code == 200, response.text identity_id = response.json()['id'] # Update identity by setting other roles body = { 'roles_to_attach': roles_to_attach, 'roles_to_detach': roles_to_detach, 'tenant': {'tenant_type': 'account', 'tenant_uuid': 'dffedd4d-b88d-444d-a9eb-6ce89aa4d2f6'}, } res = requests.patch( f'{config.QA_BASE_URL}/v2/identities/{identity_id}', json=body, headers={ 'Authorization': f'Bearer {bearer_token_user_with_vendor_star}', 'Orchard-Profile-Type': 'SettingsProfile', 'Orchard-Profile-Id': utils.OWS_ACCOUNT_TEST_USER_SETTINGS_PROFILE_ID, 'Orchard-Identity-Id': utils.OWS_ACCOUNT_TEST_USER_ID, }, ) assert res.status_code == expected_status_code, res.text if expected_status_code != 200: assert res.json() == { 'code': 'Unable to process the request because it contains invalid data.', 'message': 'Error updating identity.', } def test_update_identity_tenant_not_found( bearer_token_user_vendor_star_not_superadmin: str, create_identity_json: dict ) -> None: """Test update identity returns 404 when tenant doesn't exist.""" # First create an identity response = requests.post( f'{config.QA_BASE_URL}/v2/identities', json=create_identity_json, headers={ 'Authorization': f'Bearer {bearer_token_user_vendor_star_not_superadmin}', 'Orchard-Profile-Type': 'SettingsProfile', 'Orchard-Profile-Id': utils.OWS_PERMISSIONS_VENDOR_STAR_USER_SETTINGS_PROFILE_ID, 'Orchard-Identity-Id': utils.OWS_PERMISSIONS_VENDOR_STAR_USER_ID, }, ) assert response.status_code == 200, response.text identity_id = response.json()['id'] # Try to update with a non-existent tenant update_body = { 'roles_to_attach': ['INSIGHTS_BASE_ROLE'], 'roles_to_detach': [], 'tenant': {'tenant_type': 'account', 'tenant_uuid': '00000000-0000-0000-0000-000000000000'}, } res = requests.patch( f'{config.QA_BASE_URL}/v2/identities/{identity_id}', json=update_body, headers={ 'Authorization': f'Bearer {bearer_token_user_vendor_star_not_superadmin}', 'Orchard-Profile-Type': 'SettingsProfile', 'Orchard-Profile-Id': utils.OWS_PERMISSIONS_VENDOR_STAR_USER_SETTINGS_PROFILE_ID, 'Orchard-Identity-Id': utils.OWS_PERMISSIONS_VENDOR_STAR_USER_ID, }, ) assert res.status_code == 404, res.text assert res.json()['message'] == 'Tenant not found.'