"""Test functions related to template rendering.""" import datetime from oto import response import pytest from salessheets import config from salessheets.constants import field_const from salessheets.constants import localized_template from salessheets.constants import pdf from salessheets.logic.template_rendering import compose_artist_name from salessheets.logic.template_rendering import prepare_template_data from salessheets.logic.template_rendering import render_template from salessheets.utils import misc TEMPLATE_TO_RENDER = 'orch_template.html' WRONG_TEMPLATE_PATH = 'nonexistent.html' DATE_IN_INVALID_FORMAT = '' TEST_DATE = datetime.date(2003, 10, 29) EMPTY_ARTIST_LIST = [] ARTIST_LIST_WITH_ONE_NAME = ['Test Name'] @pytest.fixture def data_from_db(): """Use this fixture to mock data from db.""" return { 'context_type': 'physical', 'artist_list': ['Artist one', 'Artist two', 'Artist three'], 'sale_start_date': TEST_DATE, 'product_name': 'A State Of Trance 650 New Horizons', 'label': 'A State of Trance', 'upc': '8718522031700', 'product_code': 'ARMA374', 'genre': 'Dance', 'subgenre': 'Dance', 'distribution_format': 'Usb lighter sleeve', 'wholesale_price': '£40.00', 'box_lot': 50, 'vendor_name': 'some name', 'owner': 'RED', 'track_count': 20, 'track_list': { 1: {'side': [ { 'artist_name': 'Jeremy Schonfeld', 'cd': 1, 'product_id': 16690, 'track_id': 12758, 'track_name': 'Storyteller/A Day In The Lifetime', 'track_number': 1, 'type': 'performer' }, { 'artist_name': 'Jeremy Schonfeld', 'cd': 1, 'product_id': 16690, 'track_id': 10903, 'track_name': 'Common', 'track_number': 10, 'type': 'performer' }, { 'artist_name': 'Jeremy Schonfeld', 'cd': 1, 'product_id': 16690, 'track_id': 10902, 'track_name': 'Darkest Blue', 'track_number': 9, 'type': 'performer' }, { 'artist_name': 'Jeremy Schonfeld', 'cd': 1, 'product_id': 16690, 'track_id': 12623, 'track_name': 'Helluva Ride', 'track_number': 7, 'type': 'performer' }, { 'artist_name': 'Jeremy Schonfeld', 'cd': 1, 'product_id': 16690, 'track_id': 12624, 'track_name': 'No Last Calls', 'track_number': 8, 'type': 'performer' }, { 'artist_name': 'Jeremy Schonfeld', 'cd': 1, 'product_id': 16690, 'track_id': 11672, 'track_name': 'Hey Kid', 'track_number': 3, 'type': 'performer' }, { 'artist_name': 'Jeremy Schonfeld', 'cd': 1, 'product_id': 16690, 'track_id': 11670, 'track_name': "Isn't That What Life Is For", 'track_number': 6, 'type': 'performer' }, { 'artist_name': 'Jeremy Schonfeld', 'cd': 1, 'product_id': 16690, 'track_id': 11671, 'track_name': "If The World Don't Bring You Joy", 'track_number': 2, 'type': 'performer' }, { 'artist_name': 'Jeremy Schonfeld', 'cd': 1, 'product_id': 16690, 'track_id': 12024, 'track_name': 'NY Storybook', 'track_number': 5, 'type': 'performer' }, { 'artist_name': 'Jeremy Schonfeld', 'cd': 1, 'product_id': 16690, 'track_id': 11673, 'track_name': "19 Miles 'til Santa Fe", 'track_number': 4, 'type': 'performer' }]}, 2: {'side': [ { 'artist_name': 'Jeremy Schonfeld', 'cd': 2, 'product_id': 16690, 'track_id': 11930, 'track_name': 'Victims of Destiny', 'track_number': 10, 'type': 'performer' }, { 'artist_name': 'Jeremy Schonfeld', 'cd': 2, 'product_id': 16690, 'track_id': 11286, 'track_name': 'Hide Your Love Away', 'track_number': 9, 'type': 'performer' }, { 'artist_name': 'Jeremy Schonfeld', 'cd': 2, 'product_id': 16690, 'track_id': 11532, 'track_name': "Movin' On", 'track_number': 3, 'type': 'performer' }, { 'artist_name': 'Jeremy Schonfeld', 'cd': 2, 'product_id': 16690, 'track_id': 11533, 'track_name': 'Family Tree', 'track_number': 4, 'type': 'performer' }, { 'artist_name': 'Jeremy Schonfeld', 'cd': 2, 'product_id': 16690, 'track_id': 11534, 'track_name': 'NY Storybook', 'track_number': 5, 'type': 'performer' }, { 'artist_name': 'Jeremy Schonfeld', 'cd': 2, 'product_id': 16690, 'track_id': 12757, 'track_name': 'Blue Skies and All', 'track_number': 2, 'type': 'performer' }, { 'artist_name': 'Jeremy Schonfeld', 'cd': 2, 'product_id': 16690, 'track_id': 11418, 'track_name': 'Over And Done', 'track_number': 6, 'type': 'performer' }, { 'artist_name': 'Jeremy Schonfeld', 'cd': 2, 'product_id': 16690, 'track_id': 11419, 'track_name': 'For The People', 'track_number': 7, 'type': 'performer' }, { 'artist_name': 'Jeremy Schonfeld', 'cd': 2, 'product_id': 16690, 'track_id': 11420, 'track_name': 'Tom Sawyer (and the Man By His Side)', 'track_number': 8, 'type': 'performer' }, { 'artist_name': 'Jeremy Schonfeld', 'cd': 2, 'product_id': 16690, 'track_id': 12861, 'track_name': 'Nowhere Now', 'track_number': 1, 'type': 'performer' }]}}, 'large_cover_image': '../pictures/sculls.jpg', 'image_logo_orchard': '../pictures/logo.jpg', 'description': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do ' 'eiusmod tempor incididunt ut labore et dolore magna aliqua.' ' Ut enim ad minim veniam, quis nostrud exercitation ullamco ' 'laborisnisi ut aliquip ex ea commodo consequat. Duis aute irure ' 'dolor in reprehenderit in voluptate velit esse cillum dolore eu ' 'fugiat nulla pariatur. Excepteur sint occaecat cupidatat' ' non proident, sunt in culpa qui officia deserunt mollit anim ' 'id est laborum.', 'marketing_highlights': [{ 'date_added': datetime.datetime(2005, 10, 19, 9, 53, 24), 'description': 'One-sheet for the Day By Day Entertainment release Paradise ' 'Lost', 'subject': 'Day By Day Ent./Hasan Salaam - Paradise Lost'}, { 'date_added': datetime.datetime(2005, 10, 19, 17, 28, 19), 'description': 'Candlelight/Back On Black Records one-sheet for 1349 - ' 'Hellfire', 'subject': 'Plastic Head Media - Candlelight/ 1349 - ' 'Hellfire One-Sheet'}, { 'date_added': datetime.datetime(2005, 10, 19, 17, 29, 54), 'description': 'Candlelight Records one-sheet for Grimfist - ' '10 Steps To Hell', 'subject': 'Plastic Head Media - Candlelight/ Grimfist - ' '10 Steps To Hell one-sheet'}], 'sales_goals': [{ 'marketing_drivers': { 'value': 'This product is magical.', 'slogan': None }, 'country': { 'name': 'Magic Land', 'country_id': 123454321 } }, { 'marketing_drivers': { 'value': 'This product is applesauce bananas.', 'slogan': None }, 'country': { 'name': 'Applesauce Bananas', 'country_id': 100010001 } }], field_const.TEMPLATE_DETAILS_DATA: { field_const.LOCALIZED_TEMPLATE_TYPE_ID: ( localized_template.TEMPLATE_DETAILS_IDS[ localized_template.USA]) }, 'orchard_contact': {'email': 'contact@theorchard.com'}, 'user_features': {} } @pytest.fixture def non_redessent_data_physical(data_from_db): """Mock data for non redessent with physical context type.""" data_from_db[field_const.VENDOR_OWNER] = 'kadokawa_shouten' data_from_db[field_const.IMAGE_LOGO_ORCHARD] = pdf.PDF_IMAGE_LOGO_ORCHARD data_from_db[field_const.PRICING] = 0.50 data_from_db[field_const.BOX_LOT] = 100 data_from_db[field_const.EXPORTABLE] = 'yes' data_from_db[field_const.EXPLICIT] = 'yes' data_from_db[field_const.CONTEXT_TYPE] = 'physical' data_from_db[field_const.EDITION] = 'normal_edition' return data_from_db @pytest.fixture def non_redessent_data_digital(data_from_db): """Mock data for non redessent with digital context type.""" data_from_db[field_const.VENDOR_OWNER] = 'kadokawa_shouten' data_from_db[field_const.IMAGE_LOGO_ORCHARD] = pdf.PDF_IMAGE_LOGO_ORCHARD data_from_db[field_const.PRICING] = 0.50 data_from_db[field_const.BOX_LOT] = 100 data_from_db[field_const.EXPORTABLE] = 'yes' data_from_db[field_const.EXPLICIT] = 'yes' data_from_db[field_const.CONTEXT_TYPE] = 'digital' return data_from_db def test_render_template(data_from_db): """Test the function for rendering template.""" prepared_data = prepare_template_data(data_from_db) template_rendered = render_template( TEMPLATE_TO_RENDER, prepared_data.message) assert template_rendered.message.count( '

DISC') == 2 assert template_rendered.message.count( '

') == prepared_data.message[ 'track_count'] assert isinstance(template_rendered, response.Response) assert '

Lorem ipsum dolor sit amet' in ( template_rendered.message) assert 'This product is applesauce bananas.' in template_rendered.message @pytest.mark.parametrize(( 'track_list', 'disc_count', 'side_count'), [ # disc numbers and sides both ( { 1: { 'A': [ { 'product_id': 1, 'track_id': 107165, 'track_number': 1, 'cd': 1, 'side': 'A'}], 'B': [ { 'product_id': 1, 'track_id': 107164, 'track_number': 1, 'cd': 1, 'side': 'B'}, { 'product_id': 1, 'track_id': 107167, 'track_number': 2, 'cd': 1, 'side': 'B'}]}, 2: { 'A': [ { 'product_id': 1, 'track_id': 107166, 'track_number': 1, 'cd': 2, 'side': 'A'}]}}, 2, 3 ), # disc numbers no sides ( { 1: {'side': [ { 'product_id': 1, 'track_id': 107165, 'track_number': 1, 'cd': 1, 'side': None}, { 'product_id': 1, 'track_id': 107164, 'track_number': 2, 'cd': 1, 'side': None}, { 'product_id': 1, 'track_id': 107167, 'track_number': 3, 'cd': 1, 'side': None}]}, 2: {'side': [ { 'product_id': 1, 'track_id': 107166, 'track_number': 1, 'cd': 2, 'side': None}]}}, 2, 0 ), # only one track ( {1: {'A': [ { 'product_id': 1, 'track_id': 107165, 'track_number': 1, 'cd': 1, 'side': None}]}}, 0, 0 ), ]) def test_render_template_tracklist( data_from_db, track_list, disc_count, side_count): """Test the function for rendering template.""" data_from_db['track_list'] = track_list prepared_data = prepare_template_data(data_from_db) template_rendered = render_template( TEMPLATE_TO_RENDER, prepared_data.message) assert template_rendered.message.count( '

DISC') == disc_count assert template_rendered.message.count( '

SIDE') == side_count assert template_rendered.message.count( '

') == prepared_data.message[ 'track_count'] assert isinstance(template_rendered, response.Response) def test_render_template_with_wrong_template_path(data_from_db): """Test the function for rendering template. Test that the function raises an exception in case it doesn't find the template on the given path """ template_render_response = render_template( WRONG_TEMPLATE_PATH, data_from_db) assert isinstance(template_render_response, response.Response) assert template_render_response.status == 400 assert 'Template on the given path not found' in str( template_render_response.errors['code']) def test_prepare_template_data(data_from_db): """Test the function for rendering template.""" prepared_data = prepare_template_data(data_from_db) assert 'track_count' in prepared_data.message assert isinstance(prepared_data, response.Response) assert prepared_data def test_prepare_template_data_sale_start_date_is_none(data_from_db): """Test the function for rendering template if sate_start_date is None.""" data_from_db[field_const.SALE_START_DATE] = None prepared_data = prepare_template_data(data_from_db) assert isinstance(prepared_data, response.Response) assert prepared_data.message[field_const.SALE_START_DATE] == '' def test_prepare_template_data_sme_can_adjustments(data_from_db): """Test the function for rendering template if rendering SME_CAN.""" data_from_db[field_const.TEMPLATE_DETAILS_DATA][ field_const.LOCALIZED_TEMPLATE_TYPE_ID] = ( localized_template.TEMPLATE_DETAILS_IDS[localized_template.SME_CAN]) prepared_data = prepare_template_data(data_from_db) prepared_data_keys = prepared_data.message.keys() assert isinstance(prepared_data, response.Response) assert field_const.ORDER_DUE_DATE not in prepared_data_keys assert field_const.BOX_LOT not in prepared_data_keys assert field_const.PRODUCT_CODE not in prepared_data_keys def test_prepare_template_data_sme_can_adjustments_missing_field(data_from_db): """Test rendering SME_CAN template with missing popped field.""" data_from_db[field_const.TEMPLATE_DETAILS_DATA][ field_const.LOCALIZED_TEMPLATE_TYPE_ID] = ( localized_template.TEMPLATE_DETAILS_IDS[localized_template.SME_CAN]) data_from_db.pop(field_const.ORDER_DUE_DATE, None) data_from_db.pop(field_const.BOX_LOT, None) data_from_db.pop(field_const.PRODUCT_CODE, None) prepared_data = prepare_template_data(data_from_db) assert isinstance(prepared_data, response.Response) def test_prepare_template_data_japan_fields(non_redessent_data_physical): """Test preparing the japan specific fields.""" non_redessent_data_physical['sales_goals'].append({ 'marketing_drivers': { 'value': 'Itadakimasu', 'slogan': 'Banzai!' }, 'country': { 'name': 'JP', 'country_id': field_const.JAPAN_COUNTRY_ID } }) prepared_data = prepare_template_data(non_redessent_data_physical) assert prepared_data.message[field_const.EDITION] == 'Normal Edition' assert prepared_data.message[field_const.JAPAN_SLOGAN] == 'Banzai!' def test_datetime_to_string(data_from_db): """Test the function of datetime to string conversion.""" date_str = misc.datetime_to_str(data_from_db['sale_start_date']) assert date_str == '29 October 2003' assert isinstance(date_str, str) assert len(date_str) > 9 def test_compose_artist_name(data_from_db): """Test the function for composing artist name. Checks that received from database list of artist names is turned to str. """ artist_name_str = compose_artist_name(data_from_db['artist_list']) assert isinstance(artist_name_str, str) assert 'Artist one' in artist_name_str def test_compose_artist_name_empty_list(): """Test the function for composing artist name. Checks the function returns empty string in case the artist_list is empty. """ artist_name_str = compose_artist_name(EMPTY_ARTIST_LIST) assert artist_name_str == '' def test_compose_artist_name_list_with_one_name(): """Test the function for composing artist name. Checks the function returns artist name converted to string in case the artist_list has length equal to one. """ artist_name_str = compose_artist_name(ARTIST_LIST_WITH_ONE_NAME) assert artist_name_str == 'Test Name' def test_datetime_to_with_invalid_data_type(): """ Test the function of datetime to str conversion with date of wrong type. Check if an exception is raised in case the date attribute is not the datetime object """ with pytest.raises(Exception) as excinfo: misc.datetime_to_str(DATE_IN_INVALID_FORMAT) assert 'Date should be the datetime object!' in str(excinfo.value) def test_render_with_feature_flag_and_non_redessent_physical( non_redessent_data_physical): """Test rendering template with feature flag == True. Here vendor owner is not RED ESSENTIAL and distribution. context_type == physical """ prepared_data = prepare_template_data(non_redessent_data_physical) template_rendered = render_template( TEMPLATE_TO_RENDER, prepared_data.message) assert isinstance(template_rendered, response.Response) assert '

Lorem ipsum dolor sit amet' in str( template_rendered.message) def test_render_with_feature_flag_and_non_redessent_digital( non_redessent_data_digital): """Test rendering template with feature flag == True. Here vendor owner is not RED ESSENTIAL and distribution. context_type == digital """ prepared_data = prepare_template_data(non_redessent_data_digital) template_rendered = render_template( TEMPLATE_TO_RENDER, prepared_data.message) assert isinstance(template_rendered, response.Response) assert '

Lorem ipsum dolor sit amet' in str( template_rendered.message) def test_updating_data_when_vendor_not_redessent(data_from_db): """Test updating data when feature flag==True. This test is for patch_data_for_non_redessent_vendor testing. """ data_from_db[field_const.VENDOR_OWNER] = 'kadokawa_shouten' prepared_data = prepare_template_data(data_from_db) assert prepared_data.message[field_const.ORDER_DUE_DATE] assert ( prepared_data. message[field_const.ORDER_DUE_DATE] == misc.datetime_to_str( (TEST_DATE - datetime .timedelta(days=config.ORDER_DUE_DATE_TIMEDELTA)), pdf.ORCHARD_DATE_FORMAT)) assert ( prepared_data.message[field_const.PRODUCT_INFO_SALE_START_DATE] == misc.datetime_to_str( TEST_DATE, pdf.ORCHARD_DATE_FORMAT)) def test_render_sync_highlights(data_from_db): """Test rendering of sync highlights.""" data_from_db[field_const.USER_FEATURES] = { 'is_global_sync_highlights_enabled': True } data_from_db[field_const.MARKETING_HIGHLIGHTS].append({ 'subject': 'Project Sync Highlights', 'description': 'Sync Highlights Description'}) prepared_data = prepare_template_data(data_from_db) template_rendered = render_template( 'orch_template.html', prepared_data.message) assert 'Sync Highlights Description' in str(template_rendered.message) def test_render_japan_fields(non_redessent_data_physical): """Test rendering of the japan specific fields.""" data = non_redessent_data_physical data[field_const.USER_FEATURES] = { 'is_japan_sales_sheets_enabled': True } data[field_const.TEMPLATE_DETAILS_DATA][ field_const.LOCALIZED_TEMPLATE_TYPE_ID] = localized_template.\ TEMPLATE_DETAILS_IDS[localized_template.JP] data['sales_goals'].append({ 'marketing_drivers': { 'value': 'Itadakimasu', 'slogan': 'Banzai!' }, 'country': { 'name': 'JP', 'country_id': field_const.JAPAN_COUNTRY_ID } }) data['japan_release_name'] = 'Japan Release Name' data['japan_artist_name'] = 'Japan Artist Name' prepared_data = prepare_template_data(data) template_rendered = render_template( 'orch_header.html', prepared_data.message) assert 'Normal Edition' in str(template_rendered.message) assert 'Banzai!' in str( template_rendered.message) assert 'Japan Release Name' in str( template_rendered.message) assert 'Japan Artist Name' in str( template_rendered.message)