"""Tests for instant grat logic module.""" from copy import deepcopy import datetime from unittest.mock import patch from oto import response import pytest from backend.constants import error from backend.logic import instant_grat as instant_grat_logic from backend.models.instant_grats_persister import InstantGratPersister from backend.utils import api as api_utils from tests.testutils import mocks @pytest.fixture def fetch_grats_by_list_of_tuids_response(): """Return a list of grats for testing.""" return response.Response([ { 'tuid': 1, 'store_id': 187, 'date': datetime.datetime(2015, 5, 29, 0, 0), 'created_by': 'oa:768', 'created_at': datetime.datetime(2015, 5, 29, 10, 21, 15), 'active': 'Y' }, { 'tuid': 1, 'store_id': 1, 'date': datetime.datetime(2015, 5, 29, 0, 0), 'created_by': 'oa:768', 'created_at': datetime.datetime(2015, 5, 29, 10, 21, 15), 'active': 'Y'}]) @pytest.fixture def create_grats_data(): """Return a list of grats data for testing.""" return {'items': [ { 'tuid': 1, 'store_id': 187, 'date': datetime.datetime(year=2015, month=5, day=29) }, { 'tuid': 1, 'store_id': 1, 'date': datetime.datetime(year=2015, month=5, day=29) }]} @pytest.fixture def formatted_grats_response(fetch_grats_by_list_of_tuids_response): """Return a list of grats for testing.""" grats = deepcopy(fetch_grats_by_list_of_tuids_response.message) tuid = grats[0]['tuid'] for grat in grats: grat.pop('tuid') return [{ 'tuid': tuid, 'grats': grats}] def test_get_all_grats_by_product_id_no_grats_found(mocker, track_factory): """Test get all grats by product id returns 404 if no grats were found.""" test_product_id = 1 tracks = [ track_factory(publishers__count=2, performer__count=2), track_factory(performer__count=2, writers__count=2), track_factory() ] mocks.track_persister.get_all_by_product_id(mocker, tracks) mocks.instant_grats_persister.fetch_grats_by_list_of_tuids( mocker, response.create_not_found_response( error.INSTANT_GRATS_NOT_FOUND_MSG)) expected_result = error.INSTANT_GRATS_NOT_FOUND_MSG result = instant_grat_logic.get_all_grats_by_product_id(test_product_id) assert not result assert result.errors['message'] == expected_result def test_get_all_grats_by_product_id( mocker, mock_app, track_factory, fetch_grats_by_list_of_tuids_response, formatted_grats_response): """Test get all grats by product id for successful result.""" test_product_id = 1 tracks = [ track_factory(publishers__count=2, performer__count=2), track_factory(performer__count=2, writers__count=2), track_factory() ] mocks.track_persister.get_all_by_product_id(mocker, tracks) mocks.instant_grats_persister.fetch_grats_by_list_of_tuids( mocker, fetch_grats_by_list_of_tuids_response) expected_result = {'items': formatted_grats_response} result = instant_grat_logic.get_all_grats_by_product_id(test_product_id) assert result.message == expected_result def test_create_grats_for_product_id( mocker, track_factory, create_grats_data, fetch_grats_by_list_of_tuids_response, formatted_grats_response): """Test create new grats for product id by list of data success.""" test_product_id = 1 user_id = '1234' user_type = 'oa' tracks = [ track_factory(publishers__count=2, performer__count=2), track_factory(performer__count=2, writers__count=2), track_factory() ] expected_create_data = [ { 'date': datetime.datetime(2015, 5, 29, 0, 0), 'user_id': user_id, 'store_id': 187, 'tuid': 1, 'user_type': user_type }, { 'date': datetime.datetime(2015, 5, 29, 0, 0), 'user_id': user_id, 'store_id': 1, 'tuid': 1, 'user_type': user_type }] mocks.track_persister.get_all_by_product_id(mocker, tracks) mocks.ows_product_digital_get_product_by_id(mocker) mocks.instant_grats_persister.bulk_create_grats( mocker, api_utils.create_get_list_response( fetch_grats_by_list_of_tuids_response.message)) expected_result = { 'items': formatted_grats_response, 'pagination': { 'total_records': len(formatted_grats_response), 'type': 'none'}} result = instant_grat_logic.create_grats_for_product_id( test_product_id, create_grats_data, user_id=user_id, user_type=user_type) InstantGratPersister.bulk_create_grats.assert_called_with( expected_create_data) assert result.message == expected_result @patch('backend.models.instant_grats_persister.InstantGratPersister.bulk_create_grats') def test_create_grats_for_product_id_no_tracks_found( mock_create_grats, mocker, create_grats_data): """Test create grats for product failed due to tracks absence.""" test_product_id = 1 error_msg = 'No tracks found for the provided product.' mocks.track_persister.get_all_by_product_id( mocker, response.create_not_found_response(error_msg)) result = instant_grat_logic.create_grats_for_product_id( test_product_id, create_grats_data) assert result.errors.get('message') == error_msg assert result.status == 404 mock_create_grats.assert_not_called() @patch('backend.models.instant_grats_persister.InstantGratPersister.bulk_create_grats') def test_create_grats_for_product_id_invalid_track_provided( mock_create_grats, mocker, track_factory, create_grats_data): """Test create grats for product failed due to invalid track provided.""" test_product_id = 1 wrong_tuid = 'How did this thing get to `tuid` field? O_o' create_grats_data['items'][0]['tuid'] = wrong_tuid tracks = [track_factory()] error_msg = error.NO_SUCH_TRACKS_IN_PRODUCT_MSG.format(wrong_tuid) mocks.track_persister.get_all_by_product_id(mocker, tracks) result = instant_grat_logic.create_grats_for_product_id( test_product_id, create_grats_data) assert result.errors.get('message') == error_msg assert result.status == 400 mock_create_grats.assert_not_called() def test_create_grats_for_product_id_grat_model_failed( mocker, track_factory, create_grats_data): """Test create grats for product failed due to grat persister error.""" test_product_id = 1 error_msg = 'Something went wrong while grats creating, sorry.' tracks = [ track_factory(publishers__count=2, performer__count=2), track_factory(performer__count=2, writers__count=2), track_factory() ] mocks.track_persister.get_all_by_product_id(mocker, tracks) mocks.ows_product_digital_get_product_by_id(mocker) mocks.instant_grats_persister.bulk_create_grats( mocker, response.create_fatal_response(error_msg)) result = instant_grat_logic.create_grats_for_product_id( test_product_id, create_grats_data) assert result.errors.get('message') == error_msg assert result.status == 500 def test_update_grats_by_product_id( mocker, track_factory, create_grats_data, fetch_grats_by_list_of_tuids_response, formatted_grats_response): """Test update grats for product id by list of data success.""" test_product_id = 1 tracks = [ track_factory(publishers__count=2, performer__count=2), track_factory(performer__count=2, writers__count=2), track_factory() ] mocks.track_persister.get_all_by_product_id(mocker, tracks) mocks.ows_product_digital_get_product_by_id(mocker) mocks.instant_grats_persister.bulk_update_grats( mocker, api_utils.create_get_list_response( fetch_grats_by_list_of_tuids_response.message)) expected_result = { 'items': formatted_grats_response, 'pagination': { 'total_records': len(formatted_grats_response), 'type': 'none'}} result = instant_grat_logic.update_grats_by_product_id( test_product_id, create_grats_data) assert result.message == expected_result def test_update_grats_by_product_id_no_products_found( mocker, create_grats_data): """Test update grats for product id by list of data no such tracks.""" test_product_id = 1 mocks.track_persister.get_all_by_product_id( mocker, response.Response({'items': []})) result = instant_grat_logic.update_grats_by_product_id( test_product_id, create_grats_data) assert result.status == 404 def test_create_grats_for_product_id_product_fetch_failed( mocker, track_factory, create_grats_data): """Test create grats fails when the product metadata fetch fails.""" test_product_id = 1 tracks = [track_factory()] mocks.track_persister.get_all_by_product_id(mocker, tracks) mocker.patch( 'backend.models.ows_product_digital.get_product_by_product_id', return_value=response.create_not_found_response('Product not found')) result = instant_grat_logic.create_grats_for_product_id( test_product_id, create_grats_data) assert not result assert result.status == 404 def test_create_grats_for_product_id_product_dates_unavailable( mocker, track_factory, create_grats_data): """Test create grats fails when product has no preorder or sale start date.""" test_product_id = 1 tracks = [track_factory()] mocks.track_persister.get_all_by_product_id(mocker, tracks) mocks.ows_product_digital_get_product_by_id( mocker, preorder_date=None, sale_start_date=None) result = instant_grat_logic.create_grats_for_product_id( test_product_id, create_grats_data) assert result.errors.get('message') == error.VALIDATION_ERROR_IG_PRODUCT_DATES_UNAVAILABLE_MSG assert result.status == 400 @pytest.mark.parametrize('ig_date', [ datetime.datetime(2014, 12, 31), # before preorder_date datetime.datetime(2016, 1, 1), # equal to sale_start_date (exclusive upper bound) datetime.datetime(2016, 6, 1), # after sale_start_date ]) def test_create_grats_for_product_id_date_out_of_range( mocker, track_factory, create_grats_data, ig_date): """Test create grats fails when a grat date falls outside the valid window.""" test_product_id = 1 tracks = [track_factory()] create_grats_data['items'][0]['date'] = ig_date mocks.track_persister.get_all_by_product_id(mocker, tracks) mocks.ows_product_digital_get_product_by_id( mocker, preorder_date='2015-01-01', sale_start_date='2016-01-01') result = instant_grat_logic.create_grats_for_product_id( test_product_id, create_grats_data) assert result.errors.get('message') == error.VALIDATION_ERROR_IG_DATE_OUT_OF_RANGE_MSG assert result.status == 400 def test_update_grats_by_product_id_product_fetch_failed( mocker, track_factory, create_grats_data): """Test update grats fails when the product metadata fetch fails.""" test_product_id = 1 tracks = [track_factory()] mocks.track_persister.get_all_by_product_id(mocker, tracks) mocker.patch( 'backend.models.ows_product_digital.get_product_by_product_id', return_value=response.create_not_found_response('Product not found')) result = instant_grat_logic.update_grats_by_product_id( test_product_id, create_grats_data) assert not result assert result.status == 404 def test_update_grats_by_product_id_date_out_of_range( mocker, track_factory, create_grats_data): """Test update grats fails when a grat date falls outside the valid window.""" test_product_id = 1 tracks = [track_factory()] create_grats_data['items'][0]['date'] = datetime.datetime(2014, 1, 1) mocks.track_persister.get_all_by_product_id(mocker, tracks) mocks.ows_product_digital_get_product_by_id( mocker, preorder_date='2015-01-01', sale_start_date='2016-01-01') result = instant_grat_logic.update_grats_by_product_id( test_product_id, create_grats_data) assert result.errors.get('message') == error.VALIDATION_ERROR_IG_DATE_OUT_OF_RANGE_MSG assert result.status == 400