"""Config for tests.""" from datetime import datetime from unittest.mock import MagicMock from flexmock import flexmock from oto import response from owslogger import flask_logger from owsresponse.response import Response import pytest import application from sales_goals import api from sales_goals.connectors import mysql from sales_goals.constants import header from sales_goals.features import pythonfeatures from sales_goals.models import marketing_drivers from sales_goals.models import ows_product_digital from sales_goals.models import ows_project from sales_goals.models import ows_territories from tests import dbutils @pytest.fixture def mock_app(): """Mock app.""" with application.app.app_context() as context: context.g.ows = flask_logger.Ows() context.g.ows.log = MagicMock() context.g.request_context = MagicMock() yield context class FeatureEngineAdaptor: """Mocking Class for Feature Engine. Patching the real feature flags client. """ def __init__(self): """Setting empty feature_flags by default.""" self.feature_flags = {} def force_flag(self, flag_name, flag_value): """Force a flag value. Args: flag_name (str): the name of the flag. flag_value (bool): the value of the flag. Set it to true for getting "enabled" value on getting the flag. Set false for getting "control". """ self.feature_flags[flag_name] = flag_value def get(self, flag_name): """Get a flag. Args: flag_name (str): the name of the flag to get. """ return self.feature_flags.get(flag_name) @pytest.fixture def feature_engine(mocker, mock_app): """Fixture to mock feature flags. Use it in the following way: def test_muy_feature(feature_engine): feature_engine.force_flag('my_flag', True) # run code using the flag you set. """ _feature_engine = FeatureEngineAdaptor() def get_single_feature(flag_name, *args, **kwargs): return Response( status=200, message=("enabled" if _feature_engine.get(flag_name) else "control") ) mocker.patch.object( pythonfeatures, "get_single_feature", side_effect=get_single_feature) yield _feature_engine @pytest.fixture def test_database(): """Initialize in-memory database for testing purposes.""" dbutils.db_setup_function() yield dbutils.db_teardown_function() @pytest.fixture def test_ar_database(): """Initialize in-memory database for testing purposes.""" dbutils.db_setup_function(ar=True) yield dbutils.db_teardown_function(ar=True) @pytest.fixture def valid_grass_account_vendor_id(): """Vendor id for testing.""" return 25257 @pytest.fixture def valid_post_header(valid_grass_account_vendor_id): """Return valid POST request headers. Returns: (dict): header dict """ data = { header.CONTENT_TYPE: 'application/json', header.CORRELATION_ID: '1234567890', header.GRASS_ACCOUNT_TYPE: 'vendor', header.GRASS_ACCOUNT_ID: str(valid_grass_account_vendor_id), header.ORCHARD_USER_ID: 'alw:12345' } return data @pytest.fixture def post_header_validation_schema(): """Return typical schema for POST headers. Returns: (dict): schema """ schema = { 'properties': { header.GRASS_ACCOUNT_TYPE: { 'required': False, 'example': 'vendor', 'description': 'vendor | subaccount', 'type': 'string', 'pattern': '(vendor)|(subaccount)'}, header.CONTENT_TYPE: { 'required': False, 'pattern': 'application/json', 'type': 'string'}, header.GRASS_ACCOUNT_ID: { 'required': False, 'type': 'string', 'pattern': r'^\d+$', 'description': 'vendor_id | subaccount_id'}, header.CORRELATION_ID: { 'required': False, 'type': 'string', 'description': 'UUID' }, header.ORCHARD_USER_ID: { 'required': False, 'type': 'string', 'pattern': '^(oa:|alw:)' } }, 'required': True, 'type': 'object', '$schema': 'http://json-schema.org/draft-03/schema' } return schema @pytest.fixture def valid_get_header(valid_grass_account_vendor_id): """Return valid GET request headers. Returns: (dict): header dict """ data = { header.CORRELATION_ID: '1234567890-1234567890', header.GRASS_ACCOUNT_TYPE: 'vendor', header.GRASS_ACCOUNT_ID: str(valid_grass_account_vendor_id), header.ORCHARD_USER_ID: 'oa:179', } return data @pytest.fixture def get_header_validation_schema(): """Return typical schema for GET headers. Returns: (dict): schema """ schema = { 'properties': { header.GRASS_ACCOUNT_TYPE: { 'required': False, 'example': 'vendor', 'description': 'vendor | subaccount', 'type': 'string', 'pattern': '(vendor)|(subaccount)'}, header.GRASS_ACCOUNT_ID: { 'required': False, 'type': 'string', 'pattern': r'^\d+$', 'description': 'vendor_id | subaccount_id'}, header.CORRELATION_ID: { 'required': False, 'type': 'string', 'description': 'UUID' }, header.ORCHARD_USER_ID: { 'required': False, 'type': 'string', 'pattern': '^(oa:|alw:)' } }, 'required': True, 'type': 'object', '$schema': 'http://json-schema.org/draft-03/schema' } return schema @pytest.fixture def valid_delete_header(valid_grass_account_vendor_id): """Return valid DELETE request headers. Returns: (dict): header dict """ data = { header.CORRELATION_ID: '1234567890', header.GRASS_ACCOUNT_TYPE: 'vendor', header.GRASS_ACCOUNT_ID: str(valid_grass_account_vendor_id)} return data @pytest.fixture def delete_header_validation_schema(): """Return typical schema for DELETE headers. Returns: (dict): schema """ schema = { 'properties': { header.GRASS_ACCOUNT_TYPE: { 'required': False, 'example': 'vendor', 'description': 'vendor | subaccount', 'type': 'string', 'pattern': '(vendor)|(subaccount)'}, header.GRASS_ACCOUNT_ID: { 'required': False, 'type': 'string', 'pattern': r'^\d+$', 'description': 'vendor_id | subaccount_id'}, header.CORRELATION_ID: { 'required': False, 'type': 'string', 'description': 'UUID' }, header.ORCHARD_USER_ID: { 'required': False, 'type': 'string', 'pattern': '^(oa:|alw:)' } }, 'required': True, 'type': 'object', '$schema': 'http://json-schema.org/draft-03/schema' } return schema @pytest.fixture def example_data_to_validate(): """Return some data to validate against the example validation schema. Returns: data (dict): a dict containing example data that validates against the example schema """ data = { 'apple': 1234, 'orange': '007686986', 'banana': 'nine', 'mango': 'Mexican'} return data @pytest.fixture def example_validation_schema(): """Return example JSON Draft3 Schema for testing the validator. Returns: schema (dict): JSON Draft3 Validation Schema """ schema = { '$schema': 'http://json-schema.org/draft-03/schema', 'properties': { 'apple': { 'required': True, 'type': 'integer', 'blank': True, 'minimum': 0 }, 'orange': { 'required': True, 'type': 'string', 'maxLength': 255 }, 'banana': { 'type': 'string', 'required': True, 'blank': False, 'maxLength': 10 }, 'mango': { 'required': True, 'type': 'string' } }, 'additionalProperties': False, 'required': True, 'type': 'object' } return schema @pytest.fixture def client(): """Return flask test client. Returns: flask client: flask test client """ return api.app.test_client() @pytest.fixture def app_context(): """Create an api test app fixture.""" with api.app.app_context(): yield @pytest.fixture def valid_sales_goal(): """Function that returns valid dict with data for one sales goal. Returns: dict: sales goal data """ return { 'sales_goals': { 'first_week_estimate': 50 }, 'updated_at': '2017-04-13 12:33:33.652345', 'updated_by': 'User Name', 'target_market_goals': [{ 'country': { 'id': 1, 'name': 'United States' }, 'marketing_drivers': { 'id': 1, 'value': 'Marketing drivers for United States', }, 'goals': [ { 'store': { 'id': 1, 'name': 'Amazon', }, 'label_goal_value': 20, 'distribution_goal_value': 30, }]}]} @pytest.fixture def valid_sales_goals_creation_response(): """Function that returns valid sales goals creation response. Returns: dict: sales goals data """ return { 'id': 23234, 'product_id': 34596871, 'sales_goals': { 'first_week_estimate': 50 }, 'updated_by': 'alw:543765', 'updated_at': datetime.now() } @pytest.fixture def valid_sales_goals_update_response(): """Function that returns valid sales goals update response. Returns: dict: sales goals data """ return { 'sales_goals': { 'sales_goal_id': 4232, 'first_week_estimate': 33, 'updated_at': '2017-04-13 12:33:33.652345', 'updated_by': 'User Name' }, 'target_market_goals': [ { 'country': { 'country_id': 1, 'name': 'United States' }, 'marketing_drivers': { 'marketing_driver_id': 1, 'value': 'New marketing drivers for United States' }, 'goals': [ { 'target_market_goal_id': 123, 'store': { 'store_id': 1, 'name': 'Amazon' } }, { 'target_market_goal_id': 124, 'label_goal_value': 20, 'distribution_goal_value': 30 } ] } ] } @pytest.fixture def valid_countries_get_response(): """Function that returns valid countries get response. Returns: dict: countries data. """ return { 'items': [ { 'name': 'United Kingdom', 'country_id': 2, 'stores': [ { 'name': 'Amazon', 'store_id': 1 }, { 'name': 'HMV', 'store_id': 2 }, { 'name': 'Other', 'store_id': 3 } ] }, { 'name': 'United States', 'country_id': 1, 'stores': [ { 'name': 'Amazon', 'store_id': 1 }, { 'name': 'Best Buy', 'store_id': 2 }, { 'name': 'Indie', 'store_id': 4 } ] } ] } @pytest.fixture def valid_target_market_goal_creation_response(): """Function that returns valid target market goal post response. Returns: dict: target market goal data. """ return { 'marketing_drivers': { 'marketing_driver_id': 1, 'value': 'Marketing drivers for United States' }, 'goals': [ { 'target_market_goal_id': 76, 'store': { 'store_id': 1, 'name': 'Amazon', }, 'label_goal_value': 20, 'distribution_goal_value': 30, }]} @pytest.fixture def marketing_driver_data_to_dict(): """Dictionary with MarketingDriver object data.""" return { 'marketing_driver_id': 1, 'sales_goal_id': 12345, 'value': 'Here are test marketing drivers', 'country_id': 1, 'country_name': 'United States' } @pytest.fixture def target_market_goal_data_to_dict(): """Dictionary with TargetMarketGoal object data.""" return { 'target_market_goal_id': 123, 'sales_goal_id': 12345, 'store_id': 2, 'label_goal_value': 50, 'distribution_goal_value': 30, 'country_id': 1, 'country_name': 'USA' } @pytest.fixture def sales_goal_data_to_dict(): """Dictionary with SalesGoal object data.""" return { 'sales_goal_id': 165, 'first_week_estimate': 100, 'updated_by': 'oa:1234', 'product_id': 8765432, 'updated_at': '2017-04-14 12:33:33.652345' } @pytest.fixture def context(): """Return flask app context. Returns: AppContext: flask app context. """ context = api.app.app_context() return context @pytest.fixture def add_digital_store(): """Add a digital store to the DB.""" with mysql.sales_goals_session_scope() as session: store = marketing_drivers.DigitalStore(store='Apple', customer_master_master_id=1) session.add(store) store = marketing_drivers.DigitalStore(store='Spotify', customer_master_master_id=2) session.add(store) @pytest.fixture def mock_territories(): """Mock the ows territories call (only for local).""" (flexmock(ows_territories) .should_receive('get_territories') .and_return(response.Response( [ { 'country_id': 1, 'name': 'United States', 'category': 'Country' }, { 'country_id': 13, 'name': 'Brazil', 'category': 'Country' } ]))) @pytest.fixture def mock_set_marketing_priority(): """Mock the ows product digital call (only for local).""" (flexmock(ows_product_digital) .should_receive('set_marketing_priority') .and_return(response.Response(status=200))) @pytest.fixture def mock_get_project_for_product(): """Mock the ows product digital call.""" (flexmock(ows_product_digital) .should_receive('get_project_for_product') .and_return(response.Response(status=200))) @pytest.fixture def mock_delete_project_marketing_priority_in_bulk(): """Mock the ows project manager call.""" (flexmock(ows_project) .should_receive('delete_project_marketing_priority_in_bulk') .and_return(response.Response(status=200))) @pytest.fixture def mock_get_marketing_priority(): """Mock the ows product digital call (only for local).""" (flexmock(ows_product_digital) .should_receive('get_marketing_priorities') .and_return(response.Response(status=200, message=[ { 'release_id': 1, 'country_id': 1, 'priority': 'a' } ]))) @pytest.fixture def mock_get_project_marketing_priorities(): """Mock the ows project call.""" (flexmock(ows_project) .should_receive('get_project_marketing_priorities') .and_return(response.Response(status=200)))