"""Functional tests for endpoints for single feature.""" from unittest.mock import MagicMock from owsrequest import request as requests from owsrequest import error_response import pytest from features.connectors import redis from features.constants import header from features.models import split_feature from features.models import ows_users from features.constants import context as context_constants from json import dumps def create_mock_response(status_code, message): """Create a mock response for requests.get.""" mock_response = MagicMock() mock_response.status_code = status_code mock_response.json.return_value = message return mock_response @pytest.mark.parametrize( ( 'user_id', 'feature', 'headers', 'ows_users_response', 'expected_result_code', 'expected_result_message', ), [ # oa user, no headers ( 'oa:555', 'feature_2', None, create_mock_response( status_code=200, message={ 'type': 'oa', 'account': {'vendor_id': None, 'subaccount_id': None}, }, ), 200, 'variant_2', ), # oa user, user forced variant ( 'oa:123', 'feature_2', None, create_mock_response( status_code=200, message={ 'type': 'oa', 'account': {'vendor_id': None, 'subaccount_id': None}, }, ), 200, 'variant_1', ), # alw user, no forced variant ( 'alw:123', 'feature_2', None, create_mock_response( status_code=200, message={ 'type': 'alw', 'account': {'vendor_id': 999, 'subaccount_id': None}, }, ), 200, 'variant_2', ), # alw user, vendor forced variant ( 'alw:123', 'feature_2', None, create_mock_response( status_code=200, message={ 'type': 'alw', 'account': {'vendor_id': 7123, 'subaccount_id': None}, }, ), 200, 'variant_1', ), # feature nonexistant ( 'oa:123', 'feature_99999', None, create_mock_response( status_code=200, message={ 'type': 'oa', 'account': {'vendor_id': None, 'subaccount_id': None}, }, ), 404, None, ), ], ) def test_get_user_feature_functional( client, monkeypatch, user_id, feature, headers, ows_users_response, expected_result_code, expected_result_message, ): """Test get vendor user features.""" if ows_users_response: monkeypatch.setattr(redis.client, 'get', MagicMock(return_value=None)) monkeypatch.setattr(redis.client, 'set', MagicMock()) monkeypatch.setattr(requests, 'get', MagicMock(return_value=ows_users_response)) response = client.get( '/features/{}/user/{}'.format(feature, user_id), headers=headers ) assert response.status_code == expected_result_code if expected_result_message is not None: assert response.get_data().decode() == expected_result_message if ows_users_response: assert requests.get.called @pytest.mark.parametrize( ( 'user_id', 'feature', 'headers', 'ows_users_response', 'expected_result_code', 'expected_result_message', ), [ # inconsistent header ('oa:123', 'feature_2', {header.ORCHARD_USER_ID: 'oa:555'}, None, 200, None), # incomplete header ( 'oa:123', 'feature_2', {header.ORCHARD_USER_ID: 'oa:555', header.GRASS_ACCOUNT_ID: '7123'}, None, 200, None, ), ], ) def test_get_oa_user_feature_functional( client, monkeypatch, user_id, feature, headers, ows_users_response, expected_result_code, expected_result_message, ): """Test get vendor user features.""" if ows_users_response: monkeypatch.setattr(redis.client, 'get', MagicMock(return_value=None)) monkeypatch.setattr(redis.client, 'set', MagicMock()) monkeypatch.setattr(requests, 'get', MagicMock(return_value=ows_users_response)) user_response_message = { 'type': 'alw', 'user_id': 'alw:16088', 'account': {'vendor_id': 7123, 'subaccount_id': None}, } mock_response = MagicMock() mock_response.status = 200 mock_response.json = MagicMock(return_value=user_response_message) monkeypatch.setattr( ows_users, 'get_user_details_by_user_id', MagicMock(return_value=mock_response) ) response = client.get( '/features/{}/user/{}'.format(feature, user_id), headers=headers ) assert response.status_code == expected_result_code if expected_result_message is not None: assert response.get_data().decode() == expected_result_message if ows_users_response: assert requests.get.called @pytest.mark.parametrize( ( 'headers', 'feature', 'ows_users_response', 'split_response', 'expected_result_code', 'expected_result_message', ), [ # no headers, from split.io ( None, 'feature_3', None, MagicMock(return_value=context_constants.FEATURE_ENABLED), 200, context_constants.FEATURE_ENABLED, ), # no headers ( None, 'feature_2', None, MagicMock(return_value=context_constants.SPLIT_NOT_AVAILABLE), 200, 'variant_2', ), # bad headers for user context ( {header.GRASS_ACCOUNT_TYPE: 'vendor'}, 'feature_3', None, MagicMock(return_value=context_constants.SPLIT_NOT_AVAILABLE), 400, dumps(error_response.create_error_incomplete_account_headers().errors), ), # bad headers for user context ( {header.GRASS_ACCOUNT_ID: 123}, 'feature_3', None, MagicMock(return_value=context_constants.SPLIT_NOT_AVAILABLE), 400, dumps(error_response.create_error_incomplete_account_headers().errors), ), # bad headers for profile context ( {header.ORCHARD_PROFILE_TYPE: 'vendor'}, 'feature_3', None, MagicMock(return_value=context_constants.SPLIT_NOT_AVAILABLE), 400, dumps(error_response.create_error_incomplete_account_headers().errors), ), # bad headers for profile context ( {header.ORCHARD_PROFILE_ID: 123}, 'feature_3', None, MagicMock(return_value=context_constants.SPLIT_NOT_AVAILABLE), 400, dumps(error_response.create_error_incomplete_account_headers().errors), ), # non-existant feature ( None, 'feature_9999', None, MagicMock(return_value=context_constants.SPLIT_NOT_AVAILABLE), 404, None, ), # oa user in header ( {header.ORCHARD_USER_ID: 'oa:555'}, 'feature_2', create_mock_response( status_code=200, message={ 'type': 'oa', 'account': {'vendor_id': None, 'subaccount_id': None}, }, ), MagicMock(return_value=context_constants.SPLIT_NOT_AVAILABLE), 200, 'variant_2', ), # oa user in header, forced user variant ( {header.ORCHARD_USER_ID: 'oa:123'}, 'feature_2', create_mock_response( status_code=200, message={ 'type': 'oa', 'account': {'vendor_id': None, 'subaccount_id': None}, }, ), MagicMock(return_value=context_constants.SPLIT_NOT_AVAILABLE), 200, 'variant_1', ), # alw user in header, no forced variant ( {header.ORCHARD_USER_ID: 'alw:555'}, 'feature_2', create_mock_response( status_code=200, message={ 'type': 'alw', 'account': {'vendor_id': 9999, 'subaccount_id': None}, }, ), MagicMock(return_value=context_constants.SPLIT_NOT_AVAILABLE), 200, 'variant_2', ), # alw user in header, vendor forced variant ( {header.ORCHARD_USER_ID: 'alw:555'}, 'feature_2', create_mock_response( status_code=200, message={ 'type': 'alw', 'account': {'vendor_id': 9999, 'subaccount_id': None}, }, ), MagicMock(return_value=context_constants.SPLIT_NOT_AVAILABLE), 200, 'variant_2', ), # alw user and account type and account id in header, # vendor forced variant ( { header.GRASS_ACCOUNT_TYPE: 'vendor', header.GRASS_ACCOUNT_ID: 7129, header.ORCHARD_USER_ID: 'alw:16888', }, 'feature_2', create_mock_response( status_code=200, message={ 'type': 'alw', 'account': {'vendor_id': 7129, 'subaccount_id': None}, }, ), MagicMock(return_value=context_constants.SPLIT_NOT_AVAILABLE), 200, 'variant_2', ), # alw user and account type and account id in header, # vendor forced variant ( { header.GRASS_ACCOUNT_TYPE: 'vendor', header.GRASS_ACCOUNT_ID: 7123, header.ORCHARD_USER_ID: 'alw:16888', }, 'feature_2', create_mock_response( status_code=200, message={ 'type': 'alw', 'account': {'vendor_id': 7123, 'subaccount_id': None}, }, ), MagicMock(return_value=context_constants.SPLIT_NOT_AVAILABLE), 200, 'variant_1', ), # alw user and account type and account id in header, # vendor forced variant, from split.io ( { header.GRASS_ACCOUNT_TYPE: 'vendor', header.GRASS_ACCOUNT_ID: 7122, header.ORCHARD_USER_ID: 'alw:16888', }, 'feature_2', create_mock_response( status_code=200, message={ 'type': 'alw', 'account': {'vendor_id': 7122, 'subaccount_id': None}, }, ), MagicMock(return_value=context_constants.SPLIT_NOT_AVAILABLE), 200, 'variant_2', ), # identity id in header, vendor forced variant ( { header.ORCHARD_IDENTITY_ID: '5c548bd462501638ea3ed444', }, 'feature_2', None, MagicMock(return_value=context_constants.SPLIT_NOT_AVAILABLE), 200, 'variant_2', ), # identity id in header, vendor forced variant, from split.io ( { header.ORCHARD_IDENTITY_ID: '5c548bd462501638ea3ed999', }, 'feature_2', None, MagicMock(return_value=context_constants.FEATURE_ENABLED), 200, context_constants.FEATURE_ENABLED, ), # identity id in header, vendor forced variant, from split.io ( { header.ORCHARD_IDENTITY_ID: '5c548bd462501638ea3ed990', }, 'feature_2', None, MagicMock(return_value=context_constants.SPLIT_DISABLED), 200, context_constants.FEATURE_DISABLED, ), ], ) def test_get_split_feature_functional( client, monkeypatch, headers, feature, ows_users_response, split_response, expected_result_code, expected_result_message, ): """Test get vendor user features from split.io and features.yml.""" if ows_users_response: monkeypatch.setattr(redis.client, 'get', MagicMock(return_value=None)) monkeypatch.setattr(redis.client, 'set', MagicMock()) monkeypatch.setattr(requests, 'get', MagicMock(return_value=ows_users_response)) monkeypatch.setattr(split_feature, 'get_split_feature', split_response) response = client.get( '/features/{}?splitioEnabled=true'.format(feature), headers=headers ) assert response.status_code == expected_result_code if expected_result_message is not None: assert response.get_data().decode() == expected_result_message