"""Test for logic of project manager.""" from unittest.mock import MagicMock from unittest.mock import patch from flask import g from oto import response from owsrequest import request from owsrequest import test_utils import pytest from pythonfeatures import pythonfeatures from application import app from project_manager.constant import error_const from project_manager.constant import field_const from project_manager.constant import header_const from project_manager.constant import http_status_codes from project_manager.constant import marketing_const from project_manager.entity.project_post_request import ProjectPostRequest from project_manager.logic import project_manager from project_manager.models import mkt_priority from project_manager.models import ows_account from project_manager.models import ows_artist from project_manager.models import ows_marketing from project_manager.models import ows_product_review from project_manager.models import persister from project_manager.models import project as project_model from project_manager.util import features as features_util def test_get_project_grass_access(highlight_data, monkeypatch): """Test success case using grass headers (account type and id).""" project_id = 43 call_specs = [{ 'service': 'ows-marketing', 'method': 'GET', 'path': '/highlights/project/{}?mkt_program_id={}'.format( project_id, marketing_const.PROGRAM_MARKETING_HIGHLIGHTS), 'status_code': 200, 'json': {'items': [highlight_data]}}] monkeypatch.setattr( request, 'get', test_utils.mock_ows_requests(call_specs)) monkeypatch.setattr( persister, 'get_project_by_id', MagicMock(return_value=response.Response( status=200, message={'test': 'project'}))) monkeypatch.setattr( project_manager, 'is_owner', MagicMock(return_value=True)) with app.test_request_context(): project_manager.get_project('vendor', 7123, 43) assert persister.get_project_by_id.called assert project_manager.is_owner.called def test_get_project_internal_access(highlight_data, monkeypatch): """Test success case using no grass headers (internal access).""" project_id = 1234 call_specs = [{ 'service': 'ows-marketing', 'method': 'GET', 'path': '/highlights/project/{}?mkt_program_id={}'.format( project_id, marketing_const.PROGRAM_MARKETING_HIGHLIGHTS), 'status_code': 200, 'json': {'items': [highlight_data]}}] monkeypatch.setattr( request, 'get', test_utils.mock_ows_requests(call_specs)) monkeypatch.setattr( persister, 'get_project_by_id', MagicMock(return_value=response.Response( status=200, message={'test': 'project'}))) monkeypatch.setattr( project_manager, 'is_owner', MagicMock(return_value=True)) with app.test_request_context(): project_manager.get_project('vendor', None, 1234) assert persister.get_project_by_id.called assert not project_manager.is_owner.called def test_get_project_highlights(db_fixture, highlight_data, monkeypatch): """Test that the project's project highlight is fetched and returned.""" project_data = {'foo': 'bar'} monkeypatch.setattr( persister, 'get_project_by_id', MagicMock(return_value=response.Response(message=project_data))) highlight_response = response.Response(message=highlight_data) get_highlight = MagicMock(return_value=highlight_response) monkeypatch.setattr( ows_marketing, 'get_project_highlights_by_project_id', get_highlight) with app.test_request_context(): result = project_manager.get_project( account_type=None, account_id=None, project_id=1234) highlight_text = highlight_data.get('description') get_highlight.assert_called_with(1234) assert result.message['project_highlights'] == highlight_text def test_get_project_highlights_not_found(db_fixture, monkeypatch): """Test that project_highlights is empty if no highlight found.""" project_data = {'foo': 'bar'} monkeypatch.setattr( persister, 'get_project_by_id', MagicMock(return_value=response.Response(message=project_data))) highlight_response = response.Response(status=404) get_highlight = MagicMock(return_value=highlight_response) monkeypatch.setattr( ows_marketing, 'get_project_highlights_by_project_id', get_highlight) with app.test_request_context(): result = project_manager.get_project( account_type=None, account_id=None, project_id=1234) assert result.status == 200 assert result.message['project_highlights'] is None @patch('project_manager.models.ows_account.is_distributor') def test_add_project_distributor_missing_subaccount( mock_is_distributor, test_request_context): """Error is returned if distributor adds a project w/o subaccount_id.""" mock_is_distributor.return_value = response.Response(status=200) result = project_manager.add_project( project_code='test_project', project_name='test_project_name', artist_id=123412, subaccount_id=ProjectPostRequest.SUBACCOUNT_ID_NULL, grass_account_type=header_const.GRASS_ACCOUNT_TYPE_VENDOR, grass_account_id=123, user='alw:123', ) assert 400 == result.status assert error_const.VALIDATION_ERROR == result.errors['code'] assert error_const.ERROR_MSG_DISTRIBUTOR_MISSING_SUBACCOUNT ==\ result.errors['message'] @patch('project_manager.models.persister.insert_project') @patch('project_manager.models.ows_account.is_distributor') def test_add_project_with_vendor( mock_is_distributor, mock_insert_project, test_request_context): """Error is returned if distributor adds a project w/o subaccount_id.""" mock_is_distributor.return_value = response.Response(status=204) mock_insert_project.return_value = response.Response( status=201, message={'project_id': 5678}) result = project_manager.add_project( project_code='test_project', project_name='test_project_name', artist_id=123412, subaccount_id=ProjectPostRequest.SUBACCOUNT_ID_NULL, grass_account_type=None, grass_account_id=None, vendor_id=1234, user='alw:123', ) assert result.status == 201 assert result.message == { 'project_id': 5678, 'project_highlights': None } # TODO: Ensure insert_project is called with the correct ProjectPostRequest @patch('project_manager.models.persister.insert_project') @patch( 'project_manager.models.ows_marketing.create_project_highlights') @patch('project_manager.models.ows_account.get_vendor_id_for_subaccount_id') @patch('project_manager.models.ows_account.is_distributor') def test_add_project_with_highlight_description_when_success( mock_is_distributor, mock_get_vendor_id_for_subaccount_id, mock_create_project_highlights, mock_insert_project, test_request_context): """Project highlight description is created when project is created.""" project_id = 12378 project_highlights = 'some project highlight' mock_is_distributor.return_value = response.Response( status=204, message='account is not a distributor') mock_get_vendor_id_for_subaccount_id.return_value = 7213 mock_create_project_highlights.return_value = response.Response( status=201, message={'description': project_highlights}) mock_insert_project.return_value = response.Response( status=201, message={'project_id': project_id}) result = project_manager.add_project( project_code='test_project', project_name='test_project_name', artist_id=123412, subaccount_id=123, grass_account_type=header_const.GRASS_ACCOUNT_TYPE_SUBACCOUNT, grass_account_id=123, project_highlights=project_highlights, user='alw:123', ) mock_create_project_highlights.assert_called_once_with( project_id, project_highlights) assert result.message.get('project_highlights') is project_highlights def test_add_project_for_subaccount_missing_vendor( monkeypatch, test_request_context): """Error returned when subaccount makes a request, vendor_id not found.""" monkeypatch.setattr( ows_account, 'get_vendor_id_for_subaccount_id', MagicMock(return_value=None)) result = project_manager.add_project( project_code='test_project', project_name='test_project_name', artist_id=123412, subaccount_id=123, grass_account_type=header_const.GRASS_ACCOUNT_TYPE_SUBACCOUNT, grass_account_id=123, user='alw:123', ) assert 400 == result.status assert error_const.VALIDATION_ERROR == result.errors['code'] assert result.errors['message'] ==\ "Unable to find vendor_id for subaccount_id \'123\'" def test_add_project_is_distributor_fails(monkeypatch, test_request_context): """Test that if the is_distributor call fails, an error is returned.""" monkeypatch.setattr( ows_account, 'is_distributor', MagicMock(return_value=response.Response( status=500, message='distributor call failed'))) result = project_manager.add_project( project_code='test_project', project_name='test_project_name', artist_id=123412, subaccount_id=ProjectPostRequest.SUBACCOUNT_ID_NULL, grass_account_type=header_const.GRASS_ACCOUNT_TYPE_VENDOR, grass_account_id=123, user='alw:123', ) assert 500 == result.status assert result.message == 'distributor call failed' # TODO: Ensure insert_project is called with the correct ProjectPostRequest @patch('project_manager.models.persister.insert_project') @patch( 'project_manager.models.ows_marketing.create_project_highlights') @patch('project_manager.models.ows_account.get_vendor_id_for_subaccount_id') @patch('project_manager.models.ows_account.is_distributor') def test_add_project_with_highlight_description_when_fail( mock_is_distributor, mock_get_vendor_id_for_subaccount_id, mock_create_project_highlights, mock_insert_project, test_request_context): """Project is created when project highlights encounter an issue. Project highlight data should be in the payload. """ project_id = 12378 project_highlights = 'some project highlight' mock_is_distributor.return_value = response.Response( status=204, message='account is not a distributor') mock_get_vendor_id_for_subaccount_id.return_value = 7213 error_response = response.create_error_response( 'validation_error', 'something not right') mock_create_project_highlights.return_value = error_response mock_insert_project.return_value = response.Response( status=201, message={'project_id': project_id}) result = project_manager.add_project( project_code='test_project', project_name='test_project_name', artist_id=123412, subaccount_id=ProjectPostRequest.SUBACCOUNT_ID_NULL, grass_account_type=header_const.GRASS_ACCOUNT_TYPE_VENDOR, grass_account_id=123, project_highlights=project_highlights, user='alw:123', ) mock_create_project_highlights.assert_called_once_with( project_id, project_highlights) assert mock_insert_project.called assert result.status == 201 assert result.message['project_highlights'] is None # TODO: Ensure insert_project is called with the correct ProjectPostRequest @patch('project_manager.models.persister.insert_project') @patch( 'project_manager.models.ows_marketing.create_project_highlights') @patch('project_manager.models.ows_account.get_vendor_id_for_subaccount_id') @patch('project_manager.models.ows_account.is_distributor') def test_add_project_with_no_highlight( mock_is_distributor, mock_get_vendor_id_for_subaccount_id, mock_create_project_highlights, mock_insert_project, test_request_context): """Test that project highlight description created when project created.""" mock_is_distributor.return_value = response.Response( status=204, message='account is not a distributor') mock_get_vendor_id_for_subaccount_id.return_value = 7213 mock_insert_project.return_value = response.Response( status=201, message={}) result = project_manager.add_project( project_code='test_project', project_name='test_project_name', artist_id=123412, subaccount_id=ProjectPostRequest.SUBACCOUNT_ID_NULL, grass_account_type=header_const.GRASS_ACCOUNT_TYPE_VENDOR, grass_account_id=123, user='alw:123', ) mock_create_project_highlights.assert_not_called() assert mock_insert_project.called assert result.status == 201 assert result.message['project_highlights'] is None @patch('project_manager.models.persister.insert_project') @patch( 'project_manager.models.ows_marketing.create_project_highlights') @patch('project_manager.models.ows_account.get_vendor_id_for_subaccount_id') @patch('project_manager.models.ows_account.is_distributor') def test_add_project_with_create_error( mock_is_distributor, mock_get_vendor_id_for_subaccount_id, mock_create_project_highlights, mock_insert_project, test_request_context): """Test that 400 is retured with messages from model layer.""" mock_is_distributor.return_value = response.Response( status=204, message='account is not a distributor') mock_get_vendor_id_for_subaccount_id.return_value = 7213 mock_insert_project.return_value = response.create_error_response( code='some_error_code', message={'project_code': 'some error message'}, status=400) result = project_manager.add_project( project_code='test_project', project_name='test_project_name', artist_id=123412, subaccount_id=ProjectPostRequest.SUBACCOUNT_ID_NULL, grass_account_type=header_const.GRASS_ACCOUNT_TYPE_VENDOR, grass_account_id=123, user='alw:123', ) mock_create_project_highlights.assert_not_called() assert mock_insert_project.called assert result.status == 400 assert result.errors['message'] == {'project_code': 'some error message'} def test_add_project_for_distributor_with_invalid_subaccount( monkeypatch, test_request_context): """Error returned when distributor makes call to not their subaccount.""" monkeypatch.setattr( ows_account, 'is_distributor', MagicMock(return_value=response.Response(status=200))) monkeypatch.setattr( ows_account, 'get_vendor_id_for_subaccount_id', MagicMock(return_value=7123)) monkeypatch.setattr( ows_account, 'is_subaccount_for_vendor', MagicMock(return_value=response.Response( status=403, message='invalid subaccount for vendor'))) result = project_manager.add_project( project_code='test_project', project_name='test_project_name', artist_id=123412, subaccount_id=123, grass_account_type=header_const.GRASS_ACCOUNT_TYPE_VENDOR, grass_account_id=123, user='alw:123', ) assert 403 == result.status assert result.message == 'invalid subaccount for vendor' def test_add_project_for_vendor_with_subaccount( monkeypatch, test_request_context): """Error is returned if a non-distributor makes a call for a subaccount.""" monkeypatch.setattr( ows_account, 'is_distributor', MagicMock(return_value=response.Response(status=204))) result = project_manager.add_project( project_code='test_project', project_name='test_project_name', artist_id=123412, subaccount_id=123, grass_account_type=header_const.GRASS_ACCOUNT_TYPE_VENDOR, grass_account_id=123, user='alw:123', ) assert 400 == result.status assert error_const.VALIDATION_ERROR == result.errors['code'] assert result.errors['message'] ==\ 'non-distributor cannot create project for subaccount' def test_add_project_for_vendor( monkeypatch, test_request_context): """Test that a vendor can successfully add a project.""" monkeypatch.setattr( ows_account, 'is_distributor', MagicMock(return_value=response.Response(status=204))) monkeypatch.setattr( persister, 'insert_project', MagicMock(return_value=response.Response( status=200, message={'test': 'project'}))) result = project_manager.add_project( project_code='test_project', project_name='test_project_name', artist_id=123412, subaccount_id=ProjectPostRequest.SUBACCOUNT_ID_NULL, grass_account_type=header_const.GRASS_ACCOUNT_TYPE_VENDOR, grass_account_id=123, user='alw:123', ) assert 200 == result.status persister.insert_project.assert_called_once() def test_add_project_for_subaccount( monkeypatch, test_request_context): """Test that a subaccount can successfully add a project.""" monkeypatch.setattr( ows_account, 'is_distributor', MagicMock(return_value=response.Response(status=200))) monkeypatch.setattr( ows_account, 'get_vendor_id_for_subaccount_id', MagicMock(return_value=7123)) monkeypatch.setattr( ows_account, 'is_subaccount_for_vendor', MagicMock(return_value=response.Response(status=200))) monkeypatch.setattr( persister, 'insert_project', MagicMock(return_value=response.Response( status=200, message={'test': 'project'}))) result = project_manager.add_project( project_code='test_project', project_name='test_project_name', artist_id=123412, subaccount_id=123, grass_account_type=header_const.GRASS_ACCOUNT_TYPE_VENDOR, grass_account_id=123, user='alw:123', ) assert 200 == result.status persister.insert_project.assert_called_once() def test_add_project_with_artist_metadata( monkeypatch, test_request_context): """Test that an artist is created successfully and added to project.""" monkeypatch.setattr( ows_account, 'is_distributor', MagicMock(return_value=response.Response(status=200))) monkeypatch.setattr( ows_account, 'get_vendor_id_for_subaccount_id', MagicMock(return_value=7123)) monkeypatch.setattr( ows_account, 'is_subaccount_for_vendor', MagicMock(return_value=response.Response(status=200))) monkeypatch.setattr( persister, 'insert_project', MagicMock(return_value=response.Response( status=200, message={'test': 'project'}))) monkeypatch.setattr( ows_artist, 'create_artist_info', MagicMock(return_value=response.Response( status=200, message={'id': 123}))) result = project_manager.add_project( project_code='test_project', project_name='test_project_name', subaccount_id=123, grass_account_type=header_const.GRASS_ACCOUNT_TYPE_VENDOR, grass_account_id=123, artist_id=None, artist={'name': 'name', 'vendor_id': 123, 'subaccount_id': 0}, user='alw:123', ) assert 200 == result.status ows_artist.create_artist_info.assert_called_once() persister.insert_project.assert_called_once() @pytest.mark.parametrize( ('vendor_id', 'subaccount_id', 'expected_status_code'), [ # Subaccount does not belog to vendor. (6789, 2345, http_status_codes.FORBIDDEN), # vendor_id and subaccount_id both not set. (None, None, http_status_codes.BAD_REQUEST), # subaccount_id of owner passed as vendor_id (2345, None, http_status_codes.FORBIDDEN), # vendor_id of owner passed as subaccount_id (None, 1234, http_status_codes.FORBIDDEN), # Vendor is not project owner. (6789, None, http_status_codes.FORBIDDEN), # Vendor is project owner. (1234, None, http_status_codes.OK), # Subaccount is not project owner. (None, 7890, http_status_codes.FORBIDDEN), # Subaccount is project owner. (None, 2345, http_status_codes.OK) ]) def test_check_project_ownership_with_model_success( vendor_id, subaccount_id, expected_status_code, test_request_context, mocker): """Test check_project_ownership with model layer success.""" mocker.patch.object( persister, 'get_project_by_id', return_value=response.Response( message={ field_const.VENDOR_ID: 1234, field_const.SUBACCOUNT_ID: 2345}), autospec=True) ownership_response = project_manager.check_project_ownership( 32, vendor_id, subaccount_id) assert ownership_response.status == expected_status_code def test_check_project_ownership_project_fetch_error(mocker, db_fixture): """Test check_project_ownership with project fetch error.""" status_code = 987654 mocker.patch.object( persister, 'get_project_by_id', return_value=response.Response(status=status_code), autospec=True) ownership_response = project_manager.check_project_ownership(32) assert ownership_response.status == status_code @pytest.mark.parametrize( ('account_type', 'account_id', 'vendor_id', 'subaccount_id', 'is_owner'), [ # Vendor is project owner. (header_const.GRASS_ACCOUNT_TYPE_VENDOR, 1234, 1234, 0, True), # Vendor is not project owner. (header_const.GRASS_ACCOUNT_TYPE_VENDOR, 1234, 6789, 0, False), # Subaccount is project owner. (header_const.GRASS_ACCOUNT_TYPE_SUBACCOUNT, 2345, 1234, 2345, True), # Subaccount is not project owner. (header_const.GRASS_ACCOUNT_TYPE_SUBACCOUNT, 2345, 1234, 7890, False) ]) def test_is_owner( account_type, account_id, vendor_id, subaccount_id, is_owner): """Test if a vendor / subaccount owns a project.""" project = { field_const.VENDOR_ID: vendor_id, field_const.SUBACCOUNT_ID: subaccount_id} assert project_manager.is_owner( account_type, account_id, project) == is_owner def test_is_vendor_project_owner(): """Test if a vendor owns a project.""" project = {field_const.VENDOR_ID: 1234} assert project_manager.is_vendor_project_owner(project, 1234) assert not project_manager.is_vendor_project_owner(project, 2345) def test_is_subaccount_project_owner(): """Test if a subaccount owns a project.""" project = {field_const.SUBACCOUNT_ID: 1234} assert project_manager.is_subaccount_project_owner(project, 1234) assert not project_manager.is_subaccount_project_owner(project, 2345) def test_get_bulk_projects_filters_non_owned(monkeypatch): """Owned projects are returned; non-owned and missing ids become None.""" owned = {'project_id': 1, 'project_name': 'Owned', 'vendor_id': 7} not_owned = {'project_id': 2, 'project_name': 'Other', 'vendor_id': 9} monkeypatch.setattr( persister, 'get_projects_by_ids', MagicMock(return_value=response.Response( message=[owned, not_owned]))) monkeypatch.setattr( project_manager, 'is_owner', MagicMock(side_effect=lambda acc_type, acc_id, p: p['vendor_id'] == acc_id)) result = project_manager.get_bulk_projects('vendor', 7, [1, 2, 3]) assert result.message['projects'] == [owned, None, None] persister.get_projects_by_ids.assert_called_once_with([1, 2, 3]) def test_get_bulk_projects_internal_skips_ownership(monkeypatch): """Without an account context ownership is not applied (internal call).""" projects = [ {'project_id': 1, 'project_name': 'A'}, {'project_id': 2, 'project_name': 'B'}, ] monkeypatch.setattr( persister, 'get_projects_by_ids', MagicMock(return_value=response.Response(message=projects))) monkeypatch.setattr( project_manager, 'is_owner', MagicMock(return_value=False)) result = project_manager.get_bulk_projects(None, None, [1, 2]) assert result.message['projects'] == projects assert not project_manager.is_owner.called def test_get_bulk_projects_empty(monkeypatch): """Empty id list returns an empty aligned list.""" monkeypatch.setattr( persister, 'get_projects_by_ids', MagicMock(return_value=response.Response(message=[]))) result = project_manager.get_bulk_projects('vendor', 7, []) assert result.message['projects'] == [] def test_get_product_genres(mocker): """Assert that expected product genre options are returned.""" expected_message = 'test message' mocker.patch.object( persister, 'get_product_genres', return_value=response.Response(expected_message), autospec=True ) product_genres_response = project_manager.get_product_genres() assert product_genres_response assert product_genres_response.message == expected_message def test_get_product_imprints_with_unsuccessful_project_fetch( mocker, db_fixture): """Assert that an error response is returned.""" account_type = 'test account type' account_id = 1 project_id = 1 project_response = response.Response(message='applesauce', status=400) mocker.patch.object( project_manager, '_get_project', autospec=True, return_value=project_response) mocker.patch.object( persister, 'get_product_imprints_for_subaccount', autospec=True) mocker.patch.object( persister, 'get_product_imprints_for_vendor', autospec=True) product_imprints_response = project_manager.get_product_imprints( project_id, account_type, account_id) project_manager._get_project.assert_called_once_with( account_type, account_id, project_id) assert not persister.get_product_imprints_for_subaccount.called assert not persister.get_product_imprints_for_vendor.called assert not product_imprints_response assert product_imprints_response.message == project_response.message @pytest.mark.parametrize( ('account_type', 'account_id'), [ (header_const.GRASS_ACCOUNT_TYPE_VENDOR, 11), (header_const.GRASS_ACCOUNT_TYPE_SUBACCOUNT, 12), (None, None) ]) @pytest.mark.parametrize( ('project_message', 'persister_name', 'persister_called_with'), [ ({field_const.VENDOR_ID: 1, field_const.SUBACCOUNT_ID: 2}, 'get_product_imprints_for_subaccount', 2), ({field_const.VENDOR_ID: 2, field_const.SUBACCOUNT_ID: 0}, 'get_product_imprints_for_vendor', 2) ]) def test_get_product_imprints( account_type, account_id, project_message, persister_name, persister_called_with, mocker, db_fixture): """Assert that expected product imprint options are returned.""" project_id = 1 expected_response = response.Response(message='test message') mocker.patch.object( project_manager, '_get_project', autospec=True, return_value=response.Response(message=project_message)) mocker.patch.object( persister, persister_name, autospec=True, return_value=expected_response) product_imprints_response = project_manager.get_product_imprints( project_id, account_type, account_id) project_manager._get_project.assert_called_once_with( account_type, account_id, project_id) getattr(persister, persister_name).assert_called_once_with( persister_called_with) assert product_imprints_response assert product_imprints_response.message == expected_response.message def test_get_product_subgenres(mocker): """Assert that the expected product subgenre options are returned.""" expected_message = 'test message' genre_id = "doesn\'t matter for this test" mocker.patch.object( persister, 'get_product_subgenres', return_value=response.Response(expected_message) ) product_subgenres_response = project_manager.get_product_subgenres( genre_id ) assert product_subgenres_response assert product_subgenres_response.message == expected_message def test_get_product_types(mocker): """Assert that the expected product subgenre options are returned.""" expected_message = 'test message' mocker.patch.object( persister, 'get_product_types', return_value=response.Response(expected_message) ) product_types_response = project_manager.get_product_types() assert product_types_response assert product_types_response.message == expected_message def test_get_products_for_project_logic( test_request_context, project_highlight_ok, get_company_brand, mock_vendor_data, mocker, db_fixture, projects): """Assert that expected products are returned for a project. Asserts that a 200 is returned with a set of products with correct attributes. """ mocker.patch.object( ows_artist, 'get_artist_info', return_value=response.Response(message={'name': 'Rob'})) mocker.patch.object( ows_marketing, 'get_project_highlights_by_project_id', return_value=test_utils.mock_ows_requests([ project_highlight_ok])) mocker.patch.object( ows_account, 'get_vendor_company_brand', return_value=get_company_brand) mocker.patch.object( ows_account, 'get_vendor', return_value=mock_vendor_data) mocker.patch.object( pythonfeatures, 'get_single_feature', return_value=response.Response(message='disabled')) logic_response = project_manager.get_products_for_project( header_const.GRASS_ACCOUNT_TYPE_SUBACCOUNT, 1, 1) expected_message = { 'items': [{ 'artist_names': ['Mike Jones'], 'display_upc': '888831283041', 'upc': 888831283041, 'product_type': 'Music', 'product_type_id': 1, 'product_id': 1001, 'release_name': 'Something Strange Here', 'release_status': 'error_correction', 'is_error_correction_and_action_required': False, 'version': 'Deluxe', 'delivered_version': 'Live at Wembley', 'distribution_format': { 'id': 1, 'name': 'Digital', 'context': 'digital'}, 'format': 'Single', 'not_for_distribution': 'N', 'release_approval_status': None }, { 'artist_names': ['Mike Jones'], 'display_upc': '889845667810', 'upc': 889845667810, 'product_type': 'Music', 'product_type_id': 1, 'product_id': 1002, 'release_name': 'Something Strange Here', 'release_status': 'action_required', 'is_error_correction_and_action_required': False, 'version': 'Unremarkable', 'delivered_version': 'Live in New York', 'distribution_format': { 'id': 2, 'name': 'CD', 'context': 'physical'}, 'format': 'EP', 'not_for_distribution': 'N', 'release_approval_status': 'rejected' }, { 'artist_names': ['Mike Jones'], 'display_upc': '889845667872', 'upc': 889845667872, 'product_type': 'Music', 'product_type_id': 1, 'product_id': 1003, 'release_name': 'Something Strange Here', 'release_status': 'transfer_to_content', 'is_error_correction_and_action_required': False, 'version': 'Target Special Edition', 'delivered_version': 'Live in Berlin', 'distribution_format': { 'id': 1, 'name': 'Digital', 'context': 'digital'}, 'format': 'Full Length', 'not_for_distribution': 'N', 'release_approval_status': 'checked_in' }, { 'artist_names': ['John Mike'], 'product_type': 'Music', 'product_type_id': 1, 'product_id': 1014, 'release_name': 'Herp Derp', 'release_status': 'action_required', 'is_error_correction_and_action_required': True, 'display_upc': '803680422555', 'upc': 803680422555, 'version': 'Le 4th status', 'delivered_version': 'Remixed by Rem', 'distribution_format': { 'id': 1, 'name': 'Digital', 'context': 'digital'}, 'format': 'Single', 'not_for_distribution': 'N', 'release_approval_status': 'rejected'} ]} assert logic_response.status == 200 assert logic_response.message == expected_message def test_get_products_for_project_logic_from_contentreview( test_request_context, project_highlight_ok, get_company_brand, mocker, db_fixture, projects, mock_vendor_data): """Assert that expected products are returned for a project. Asserts that a 200 is returned with a set of products with correct attributes. """ mocker.patch.object( ows_artist, 'get_artist_info', return_value=response.Response(message={'name': 'Rob'})) mocker.patch.object( ows_account, 'get_vendor_company_brand', return_value=get_company_brand) mocker.patch.object( ows_account, 'get_vendor', return_value=mock_vendor_data) mocker.patch.object( request, 'get', return_value=test_utils.mock_ows_requests([project_highlight_ok])) mocker.patch.object( features_util, 'get_rejections_from_cr_ff_status', return_value=True, ) mocker.patch.object( ows_product_review, 'get_status', return_value=response.Response( message={ 'id': 1001, 'ec_and_ar': False, 'release_status': 'transfer_to_content', 'release_approval_status': 'test_release_approval_status', }, status=200, ), ) logic_response = project_manager.get_products_for_project( header_const.GRASS_ACCOUNT_TYPE_SUBACCOUNT, 1, 1) expected_message = { 'items': [{ 'artist_names': ['Mike Jones'], 'display_upc': '888831283041', 'upc': 888831283041, 'product_type': 'Music', 'product_type_id': 1, 'product_id': 1001, 'release_name': 'Something Strange Here', 'release_status': 'error_correction', 'is_error_correction_and_action_required': False, 'version': 'Deluxe', 'delivered_version': 'Live at Wembley', 'distribution_format': { 'id': 1, 'name': 'Digital', 'context': 'digital'}, 'format': 'Single', 'not_for_distribution': 'N', 'release_approval_status': 'test_release_approval_status' }, { 'artist_names': ['Mike Jones'], 'display_upc': '889845667810', 'upc': 889845667810, 'product_type': 'Music', 'product_type_id': 1, 'product_id': 1002, 'release_name': 'Something Strange Here', 'release_status': 'in_content', 'is_error_correction_and_action_required': False, 'version': 'Unremarkable', 'delivered_version': 'Live in New York', 'distribution_format': { 'id': 2, 'name': 'CD', 'context': 'physical'}, 'format': 'EP', 'not_for_distribution': 'N', 'release_approval_status': 'test_release_approval_status' }, { 'artist_names': ['Mike Jones'], 'display_upc': '889845667872', 'upc': 889845667872, 'product_type': 'Music', 'product_type_id': 1, 'product_id': 1003, 'release_name': 'Something Strange Here', 'release_status': 'transfer_to_content', 'is_error_correction_and_action_required': False, 'version': 'Target Special Edition', 'delivered_version': 'Live in Berlin', 'distribution_format': { 'id': 1, 'name': 'Digital', 'context': 'digital'}, 'format': 'Full Length', 'not_for_distribution': 'N', 'release_approval_status': 'test_release_approval_status' }, { 'artist_names': ['John Mike'], 'product_type': 'Music', 'product_type_id': 1, 'product_id': 1014, 'release_name': 'Herp Derp', 'release_status': 'error_correction', 'is_error_correction_and_action_required': False, 'display_upc': '803680422555', 'upc': 803680422555, 'version': 'Le 4th status', 'delivered_version': 'Remixed by Rem', 'distribution_format': { 'id': 1, 'name': 'Digital', 'context': 'digital'}, 'format': 'Single', 'not_for_distribution': 'N', 'release_approval_status': 'test_release_approval_status'} ]} assert logic_response.status == 200 assert logic_response.message == expected_message def test_get_products_for_project_logic_from_contentreview_ec_and_ar( test_request_context, project_highlight_ok, get_company_brand, mocker, db_fixture, projects, mock_vendor_data): """Assert that expected status are returned for a rejected corrections. Asserts that a 200 is returned with a set of products with correct attributes. """ mocker.patch.object( ows_artist, 'get_artist_info', return_value=response.Response(message={'name': 'Rob'})) mocker.patch.object( ows_account, 'get_vendor_company_brand', return_value=get_company_brand) mocker.patch.object( ows_account, 'get_vendor', return_value=mock_vendor_data) mocker.patch.object( request, 'get', return_value=test_utils.mock_ows_requests([project_highlight_ok])) mocker.patch.object( features_util, 'get_rejections_from_cr_ff_status', return_value=True, ) mocker.patch.object( ows_product_review, 'get_status', return_value=response.Response( message={ 'id': 1001, 'ec_and_ar': False, 'release_status': 'action_required', 'release_approval_status': 'rejected', }, status=200, ), ) logic_response = project_manager.get_products_for_project( header_const.GRASS_ACCOUNT_TYPE_SUBACCOUNT, 1, 1) expected_rejected_product = { 'artist_names': ['Mike Jones'], 'display_upc': '888831283041', 'upc': 888831283041, 'product_type': 'Music', 'product_type_id': 1, 'product_id': 1001, 'release_name': 'Something Strange Here', 'release_status': 'action_required', 'is_error_correction_and_action_required': True, 'version': 'Deluxe', 'delivered_version': 'Live at Wembley', 'distribution_format': { 'id': 1, 'name': 'Digital', 'context': 'digital'}, 'format': 'Single', 'not_for_distribution': 'N', 'release_approval_status': 'rejected' } assert logic_response.status == 200 assert expected_rejected_product in logic_response.message['items'] def test_get_product_for_project_from_contentreview_ec_unsubmit( test_request_context, project_highlight_ok, get_company_brand, mocker, db_fixture, projects, mock_vendor_data): """Assert that expected status is returned for an unsubmitted correction. Asserts that a 200 is returned with a set of products with correct attributes. """ mocker.patch.object( ows_artist, 'get_artist_info', return_value=response.Response(message={'name': 'Rob'})) mocker.patch.object( ows_account, 'get_vendor_company_brand', return_value=get_company_brand) mocker.patch.object( ows_account, 'get_vendor', return_value=mock_vendor_data) mocker.patch.object( request, 'get', return_value=test_utils.mock_ows_requests([project_highlight_ok])) mocker.patch.object( features_util, 'get_rejections_from_cr_ff_status', return_value=True, ) mocker.patch.object( ows_product_review, 'get_status', return_value=response.Response( message={ 'id': 1001, 'ec_and_ar': False, 'release_status': 'label_processing', 'release_approval_status': None, }, status=200, ), ) mocker.patch.object( persister, 'get_release_status_for_product', return_value=response.Response( message={ 'release_status': 'in_content', 'review_status': 'approved', 'correction_status': 'active' }, status=200 ) ) logic_response = project_manager.get_products_for_project( header_const.GRASS_ACCOUNT_TYPE_SUBACCOUNT, 1, 1) expected_unsubmitted_product = { 'artist_names': ['Mike Jones'], 'display_upc': '888831283041', 'upc': 888831283041, 'product_type': 'Music', 'product_type_id': 1, 'product_id': 1001, 'release_name': 'Something Strange Here', 'release_status': 'error_correction', 'is_error_correction_and_action_required': False, 'version': 'Deluxe', 'delivered_version': 'Live at Wembley', 'distribution_format': { 'id': 1, 'name': 'Digital', 'context': 'digital'}, 'format': 'Single', 'not_for_distribution': 'N', 'release_approval_status': None } assert logic_response.status == 200 assert expected_unsubmitted_product in logic_response.message['items'] def test_get_formatted_product_contentreview_status_lookup_fails( mocker): """Assert CR review lookup failures do not fall back to persisted status.""" product = { 'product_id': 1001, '_is_enabled_rejections_from_cr': True, 'version': 'Deluxe', 'delivered_version': 'Live at Wembley', 'product_type_id': 1, 'display_upc': '888831283041', 'upc': 888831283041, 'product_type': 'Music', 'release_name': 'Something Strange Here', 'distribution_format_id': 1, 'distribution_format_name': 'Digital', 'context_type': 'digital', 'format': 'Single', 'not_for_distribution': 'N', } mocker.patch.object( persister, 'get_release_status_for_product', return_value=response.Response(message={ 'release_status': 'in_content', 'review_status': 'approved', 'correction_status': 'active', }, status=200), autospec=True, ) mocker.patch.object( persister, 'get_artists_for_product', return_value=response.Response(message=['Mike Jones']), autospec=True, ) mocker.patch.object( ows_product_review, 'get_status', return_value=response.Response(message='not found', status=404), autospec=True, ) formatted_product = project_manager._get_formatted_product(product) assert formatted_product['release_approval_status'] is None assert formatted_product['release_status'] == 'error_correction' ows_product_review.get_status.assert_called_once_with(1001) def test_get_products_no_project_logic( test_request_context, mocker, db_fixture, projects, get_company_brand, mock_vendor_data): """Assert 404 when a project does not exist. Asserts that a 404 with the appropriate code and message is returned and an error is logged when a project does not exist. """ project_id = 0 mocker.patch.object( ows_account, 'get_vendor_company_brand', return_value=get_company_brand) mocker.patch.object( ows_account, 'get_vendor', return_value=mock_vendor_data) mocker.patch.object( pythonfeatures, 'get_single_feature', return_value=response.Response(message='disabled')) expected_errors = { 'code': error_const.ERROR_CODE_NOT_FOUND, 'message': 'Unable to find project_id {id}'.format(id=project_id)} logic_response = project_manager.get_products_for_project( header_const.GRASS_ACCOUNT_TYPE_SUBACCOUNT, 1, project_id) assert logic_response.status == 404 assert logic_response.errors == expected_errors g.log.warning.assert_called_once_with( 'No project found for project_id={id}'.format(id=project_id)) def test_get_products_no_products( test_request_context, highlight_data, mocker, db_fixture, projects, get_company_brand, mock_vendor_data): """Assert empty set is returned when there are no products. Asserts that an empty set of products and 200 is returned when there are no products for a valid project. """ project_id = 3 call_specs = [{ 'service': 'ows-marketing', 'method': 'GET', 'path': '/highlights/project/{}?mkt_program_id={}'.format( project_id, marketing_const.PROGRAM_MARKETING_HIGHLIGHTS), 'status_code': 200, 'json': {'items': [highlight_data]}}] mocker.patch.object( request, 'get', return_value=test_utils.mock_ows_requests(call_specs)) mocker.patch.object( ows_artist, 'get_artist_info', return_value=response.Response(message={'name': 'Rob'})) mocker.patch.object( ows_account, 'get_vendor_company_brand', return_value=get_company_brand) mocker.patch.object( ows_account, 'get_vendor', return_value=mock_vendor_data) mocker.patch.object( pythonfeatures, 'get_single_feature', return_value=response.Response(message='disabled')) logic_response = project_manager.get_products_for_project( header_const.GRASS_ACCOUNT_TYPE_SUBACCOUNT, 2, project_id) assert logic_response.status == 200 assert logic_response.message == {'items': []} def test_get_products_with_multiple_primary_artists( test_request_context, project_highlight_ok, mocker, project_id, db_fixture, projects, multiple_primary_artists, get_company_brand, mock_vendor_data): """Assert list of artist names is returned when multiple artists. Asserts that when there are multiple primary artists returned from the db their names are returned in a list. """ mocker.patch.object( request, 'get', return_value=test_utils.mock_ows_requests([project_highlight_ok])) mocker.patch.object( ows_artist, 'get_artist_info', return_value=response.Response(message={'name': 'Rob'})) mocker.patch.object( ows_account, 'get_vendor_company_brand', return_value=get_company_brand) mocker.patch.object( ows_account, 'get_vendor', return_value=mock_vendor_data) mocker.patch.object( pythonfeatures, 'get_single_feature', return_value=response.Response(message='disabled')) logic_response = project_manager.get_products_for_project( header_const.GRASS_ACCOUNT_TYPE_SUBACCOUNT, 1, project_id) product_artist_name = logic_response.message['items'][0]['artist_names'] assert logic_response.status == 200 assert product_artist_name == [ 'Mike Jones', 'Billy Bones', 'Jane Dune'] def test_get_products_with_no_primary_artists( test_request_context, highlight_data, mocker, db_fixture, projects, product_with_no_primary_artists, get_company_brand, mock_vendor_data): """Assert empty list is returned when no primary artists for a release. Asserts that when there are no primary artists returned from the db an empty list is returned """ project_id = 2 call_specs = [{ 'service': 'ows-marketing', 'method': 'GET', 'path': '/highlights/project/{}?mkt_program_id={}'.format( project_id, marketing_const.PROGRAM_MARKETING_HIGHLIGHTS), 'status_code': 200, 'json': {'items': [highlight_data]}}] mocker.patch.object( request, 'get', return_value=test_utils.mock_ows_requests(call_specs)) mocker.patch.object( ows_artist, 'get_artist_info', return_value=response.Response(message={'name': 'Rob'})) mocker.patch.object( ows_account, 'get_vendor_company_brand', return_value=get_company_brand) mocker.patch.object( ows_account, 'get_vendor', return_value=mock_vendor_data) mocker.patch.object( pythonfeatures, 'get_single_feature', return_value=response.Response(message='disabled')) logic_response = project_manager.get_products_for_project( header_const.GRASS_ACCOUNT_TYPE_SUBACCOUNT, 1, project_id) product_artist_name = logic_response.message['items'][2]['artist_names'] assert logic_response.status == 200 assert product_artist_name == [] def test_get_products_with_invalid_grass_account( test_request_context, mocker, db_fixture, projects, get_company_brand, mock_vendor_data): """Assert authorization error when subaccount has no access. Asserts that a 403 type error is returned when the subaccount does not have access. """ mocker.patch.object( ows_artist, 'get_artist_info', return_value=response.Response(message={'name': 'Rob'})) mocker.patch.object( pythonfeatures, 'get_single_feature', return_value=response.Response(message='disabled')) mocker.patch.object( ows_account, 'get_vendor_company_brand', return_value=get_company_brand) mocker.patch.object( ows_account, 'get_vendor', return_value=mock_vendor_data) logic_response = project_manager.get_products_for_project( header_const.GRASS_ACCOUNT_TYPE, 5555, 1) assert logic_response.status == 403 assert logic_response.errors['code'] == error_const.AUTHORIZATION_ERROR def test_get_products_with_oa( test_request_context, mocker, db_fixture, projects, get_company_brand, mock_vendor_data): """Assert that an Orchard Admin can get a project's products.""" mocker.patch.object( ows_artist, 'get_artist_info', return_value=response.Response(message={'name': 'Rob'})) mocker.patch.object( ows_account, 'get_vendor_company_brand', return_value=get_company_brand) mocker.patch.object( ows_account, 'get_vendor', return_value=mock_vendor_data) mocker.patch.object( pythonfeatures, 'get_single_feature', return_value=response.Response(message='disabled')) logic_response = project_manager.get_products_for_project( None, None, 1) assert logic_response.status == 200 def test_get_product_for_project( test_request_context, project_highlight_ok, mocker, project_id, db_fixture, projects, get_company_brand, mock_vendor_data): """Assert that expected product is returned for a project. Asserts that a 200 is returned with a product including the correct attributes. """ mocker.patch.object( ows_artist, 'get_artist_info', return_value=response.Response(message={'name': 'Rob'})) mocker.patch.object( request, 'get', return_value=test_utils.mock_ows_requests([project_highlight_ok])) mocker.patch.object( ows_account, 'get_vendor_company_brand', return_value=get_company_brand) mocker.patch.object( ows_account, 'get_vendor', return_value=mock_vendor_data) mocker.patch.object( pythonfeatures, 'get_single_feature', return_value=response.Response(message='disabled')) logic_response = project_manager.get_product_for_project( header_const.GRASS_ACCOUNT_TYPE_SUBACCOUNT, 1, project_id, 1003) expected_message = { 'artist_names': ['Mike Jones'], 'display_upc': '889845667872', 'upc': 889845667872, 'product_type': 'Music', 'product_type_id': 1, 'product_id': 1003, 'release_name': 'Something Strange Here', 'release_status': 'transfer_to_content', 'is_error_correction_and_action_required': False, 'version': 'Target Special Edition', 'delivered_version': 'Live in Berlin', 'distribution_format': { 'id': 1, 'name': 'Digital', 'context': 'digital' }, 'format': 'Full Length', 'not_for_distribution': 'N', 'release_approval_status': 'checked_in' } assert logic_response.status == 200 assert logic_response.message == expected_message def test_get_product_for_project_no_project( test_request_context, db_fixture, mocker, get_company_brand, mock_vendor_data): """Assert that expected not found message is returned when not found. Asserts that a 404 is returned with the appropriate message. """ mocker.patch.object( ows_account, 'get_vendor_company_brand', return_value=get_company_brand) mocker.patch.object( ows_account, 'get_vendor', return_value=mock_vendor_data) logic_response = project_manager.get_product_for_project( header_const.GRASS_ACCOUNT_TYPE_SUBACCOUNT, 1, 0, 1003) expected_error_message = 'Unable to find project_id 0' response_errors = logic_response.errors assert logic_response.status == 404 assert response_errors.get('message') == expected_error_message assert response_errors.get('code') == 'not_found_error' def test_get_product_for_project_no_product( test_request_context, project_highlight_ok, mocker, db_fixture, projects): """Assert that expected not found message is returned when not found. Asserts that a 404 is returned with the appropriate message. """ mocker.patch.object( ows_artist, 'get_artist_info', return_value=response.Response(message={'name': 'Rob'})) mocker.patch.object( request, 'get', return_value=test_utils.mock_ows_requests([project_highlight_ok])) logic_response = project_manager.get_product_for_project( header_const.GRASS_ACCOUNT_TYPE_SUBACCOUNT, 1, 1, 2143) expected_error_message = 'Unable to find product_id 2143' response_errors = logic_response.errors assert logic_response.status == 404 assert response_errors.get('message') == expected_error_message assert response_errors.get('code') == 'not_found_error' def test_get_product_with_invalid_grass_account( mocker, test_request_context, db_fixture, projects): """Assert authorization error when subaccount has no access. Asserts that a 403 type error is returned when the subaccount does not have access. """ mocker.patch.object( ows_artist, 'get_artist_info', return_value=response.Response(message={'name': 'Rob'})) logic_response = project_manager.get_product_for_project( header_const.GRASS_ACCOUNT_TYPE, 5555, 1, 1001) assert logic_response.status == 403 assert logic_response.errors['code'] == error_const.AUTHORIZATION_ERROR def test_add_project_includes_artist_id( mocker, db_fixture, test_request_context): """Assert project is created with artist id.""" mocker.patch.object( ows_account, 'get_vendor_id_for_subaccount_id', return_value='not_none') project_code = '1234' project_name = 'Some Project Name' artist_id = 21323 subaccount_id = None grass_account_type = 'subaccount' grass_account_id = '23123' user = 'alw:123' logic_response = project_manager.add_project( project_code, project_name, artist_id, subaccount_id, grass_account_type, grass_account_id, None, None, None, user, ) assert logic_response.status == 201 assert logic_response.message['artist_id'] == artist_id def test_add_project_includes_user(mocker, db_fixture, test_request_context): """Assert project is created with user id and user type.""" mocker.patch.object( ows_account, 'get_vendor_id_for_subaccount_id', return_value='not_none') project_code = '1234' project_name = 'Some Project Name' artist_id = 21323 subaccount_id = None grass_account_type = 'subaccount' grass_account_id = '23123' user = 'alw:123' logic_response = project_manager.add_project( project_code, project_name, artist_id, subaccount_id, grass_account_type, grass_account_id, None, None, None, user, ) assert logic_response.status == 201 assert logic_response.message['artist_id'] == artist_id def test_add_project_with_missing_user_error(mocker, db_fixture): """Assert that expected orchard user id missing message is returned.""" mocker.patch.object( ows_account, 'get_vendor_id_for_subaccount_id', return_value='not_none') project_code = '1234' project_name = 'Some Project Name' artist_id = 21323 subaccount_id = None grass_account_type = 'subaccount' grass_account_id = '23123' logic_response = project_manager.add_project( project_code, project_name, artist_id, subaccount_id, grass_account_type, grass_account_id) assert logic_response.status == 400 assert logic_response.errors['message'] == \ error_const.ERROR_MESSAGE_MISSING_ORCHARD_USER_ID assert logic_response.errors['code'] == \ error_const.ERROR_CODE_MISSING_ORCHARD_USER_ID @patch('project_manager.models.persister.get_project_by_id') @patch('project_manager.models.persister.update_project_by_id') @patch( 'project_manager.models.ows_marketing.update_project_highlights') @patch( 'project_manager.models.ows_marketing.get_project_highlights_by_project_id') # noqa def test_update_project_without_highlights_passed( mock_get_highlight_model, mock_update_highlight_model, mock_update_project, mock_get_project_by_id): """Update a project while returning current highlights if not provided.""" project_highlights = 'Some project highlight' project_id = 7362 update_project_data = { 'project_id': project_id, 'project_name': 'new name', 'artist_id': 12345, 'description': 'new description'} get_highlight_message = { 'attachment': 'N', 'client': 'alw', 'highlight_id': 2763, 'entity': 'project', 'mkt_program_id': 20, 'scope': 'public', 'description': project_highlights, 'entity_id': project_id, 'subject': 'Project Highlights'} user = 'alw:123' update_project_message = {'updated_date_utc': '000.000.000'} update_project_message.update(update_project_data.copy()) mock_get_project_by_id.return_value = response.Response(message={}) mock_update_project.return_value = response.Response( message=update_project_message) mock_get_highlight_model.return_value = response.Response( message=get_highlight_message) result = project_manager.update_project( None, None, project_id, update_project_data, user) expected_message = update_project_message.copy() expected_message['project_highlights'] = project_highlights mock_get_highlight_model.assert_called_once_with(project_id) mock_update_highlight_model.assert_not_called() assert result.message == expected_message @patch('project_manager.models.persister.get_project_by_id') @patch('project_manager.models.persister.update_project_by_id') @patch( 'project_manager.models.ows_marketing.update_project_highlights') @patch( 'project_manager.models.ows_marketing.get_project_highlights_by_project_id') # noqa def test_update_project_without_highlights( mock_get_highlight_model, mock_update_highlight_model, mock_update_project, mock_get_project_by_id): """Update a project when no project highlights exist for the project.""" project_id = 7362 update_project_data = { 'project_id': project_id, 'project_name': 'new name', 'artist_id': 12345, 'description': 'new description'} user = 'alw:123' update_project_message = {'updated_date_utc': '000.000.000'} update_project_message.update(update_project_data.copy()) mock_get_project_by_id.return_value = response.Response(message={}) mock_update_project.return_value = response.Response( message=update_project_message) mock_get_highlight_model.return_value = response.Response( message={}, status=404) result = project_manager.update_project( None, None, project_id, update_project_data, user) expected_message = update_project_message.copy() mock_get_highlight_model.assert_called_once_with(project_id) mock_update_highlight_model.assert_not_called() assert result.message == expected_message @patch('project_manager.models.persister.get_project_by_id') @patch('project_manager.models.persister.update_project_by_id') @patch( 'project_manager.models.ows_marketing.update_project_highlights') @patch( 'project_manager.models.ows_marketing.get_project_highlights_by_project_id') # noqa def test_update_project_with_highlights( mock_get_highlight_model, mock_update_highlight_model, mock_update_project, mock_get_project_by_id): """Update highlight associated with project when passed.""" project_id = 7362 highlight_id = 12374 new_highlight_description = 'new description of something' user = 'alw:123' get_highlight_message = { 'attachment': 'N', 'client': 'alw', 'highlight_id': highlight_id, 'entity': 'project', 'mkt_program_id': 20, 'scope': 'public', 'description': 'Old description', 'entity_id': project_id, 'subject': 'Project Highlights'} update_highlight_message = get_highlight_message.copy() update_highlight_message['description'] = new_highlight_description update_project_message = {'project_id': project_id, 'thing': 'place'} update_project_data = update_project_message.copy() update_project_data['project_highlights'] = new_highlight_description mock_get_project_by_id.return_value = response.Response(message={}) mock_get_highlight_model.return_value = response.Response( message=get_highlight_message) mock_update_highlight_model.return_value = response.Response( message=update_highlight_message) mock_update_project.return_value = response.Response( message=update_project_message) result = project_manager.update_project( None, None, project_id, update_project_data, user) mock_get_highlight_model.assert_called_once_with(project_id) mock_update_highlight_model.assert_called_once_with( highlight_id, new_highlight_description) assert result.message['project_highlights'] == new_highlight_description @patch('project_manager.models.persister.get_project_by_id') @patch('project_manager.models.persister.update_project_by_id') @patch( 'project_manager.models.ows_marketing.update_project_highlights') @patch( 'project_manager.models.ows_marketing.get_project_highlights_by_project_id') # noqa def test_update_project_with_highlights_blank( mock_get_highlight_model, mock_update_highlight_model, mock_update_project, mock_get_project_by_id): """Update highlight associated with project when passed.""" project_id = 7362 highlight_id = 12374 new_highlight_description = '' user = 'alw:123' get_highlight_message = { 'attachment': 'N', 'client': 'alw', 'highlight_id': highlight_id, 'entity': 'project', 'mkt_program_id': 20, 'scope': 'public', 'description': 'Old description', 'entity_id': project_id, 'subject': 'Project Highlights'} update_highlight_message = get_highlight_message.copy() update_highlight_message['description'] = new_highlight_description update_project_message = {'project_id': project_id, 'thing': 'place'} update_project_data = update_project_message.copy() update_project_data['project_highlights'] = new_highlight_description mock_get_project_by_id.return_value = response.Response(message={}) mock_get_highlight_model.return_value = response.Response( message=get_highlight_message) mock_update_highlight_model.return_value = response.Response( message=update_highlight_message) mock_update_project.return_value = response.Response( message=update_project_message) result = project_manager.update_project( None, None, project_id, update_project_data, user) mock_get_highlight_model.assert_called_once_with(project_id) mock_update_highlight_model.assert_called_once_with( highlight_id, new_highlight_description) assert result.message['project_highlights'] == new_highlight_description @patch('project_manager.models.persister.get_project_by_id') @patch('project_manager.models.persister.update_project_by_id') @patch( 'project_manager.models.ows_marketing.update_project_highlights') @patch( 'project_manager.models.ows_marketing.get_project_highlights_by_project_id') # noqa def test_update_project_with_highlights_get_project_highlights_fail( mock_get_highlight_model, mock_update_highlight_model, mock_update_project, mock_get_project_by_id): """Test response when get_project_highlights_by_project_id fails.""" project_id = 7362 new_highlight_description = 'new description of something' user = 'alw:123' update_project_message = {'project_id': project_id, 'thing': 'place'} update_project_data = update_project_message.copy() update_project_data['project_highlights'] = new_highlight_description mock_get_project_by_id.return_value = response.Response(message={}) mock_get_highlight_model.return_value = response.create_error_response( code='some_error', message='Something happened') mock_update_highlight_model.return_value = response.create_error_response( code='some_error', message='Something happened') mock_update_project.return_value = response.Response( message=update_project_message) result = project_manager.update_project( None, None, project_id, update_project_data, user) mock_get_highlight_model.assert_called_once_with(project_id) mock_update_highlight_model.assert_not_called() assert result.message.get('project_highlights') is None @patch('project_manager.models.persister.get_project_by_id') @patch('project_manager.models.persister.update_project_by_id') @patch( 'project_manager.models.ows_marketing.update_project_highlights') @patch( 'project_manager.models.ows_marketing.get_project_highlights_by_project_id') # noqa def test_update_project_with_highlights_update_project_highlights_fail( mock_get_highlight_model, mock_update_highlight_model, mock_update_project, mock_get_project_by_id): """Test response when get_project_highlights_by_project_id fails.""" project_id = 7362 highlight_id = 12374 new_highlight_description = 'new description of something' old_highlight_description = 'old description of something' get_highlight_message = { 'attachment': 'N', 'client': 'alw', 'highlight_id': highlight_id, 'entity': 'project', 'mkt_program_id': 20, 'scope': 'public', 'description': old_highlight_description, 'entity_id': project_id, 'subject': 'Project Highlights'} user = 'alw:123' update_project_message = { 'project_id': project_id, 'thing': 'place'} update_project_data = update_project_message.copy() update_project_data['project_highlights'] = new_highlight_description mock_get_project_by_id.return_value = response.Response(message={}) mock_get_highlight_model.return_value = response.Response( message=get_highlight_message) mock_update_highlight_model.return_value = response.create_error_response( code='some_error', message='Something happened') mock_update_project.return_value = response.Response( message=update_project_message) result = project_manager.update_project( None, None, project_id, update_project_data, user) mock_get_highlight_model.assert_called_once_with(project_id) mock_update_highlight_model.assert_called_once_with( highlight_id, new_highlight_description) assert result.status == 200 assert result.message.get( 'project_highlights') == old_highlight_description @patch( 'project_manager.models.ows_marketing.create_project_highlights') @patch('project_manager.models.persister.get_project_by_id') @patch('project_manager.models.persister.update_project_by_id') @patch( 'project_manager.models.ows_marketing.update_project_highlights') @patch( 'project_manager.models.ows_marketing.get_project_highlights_by_project_id') # noqa def test_update_project_with_highlights_highlight_not_found( mock_get_highlight_model, mock_update_highlight_model, mock_update_project, mock_get_project_by_id, mock_create_highlight_model): """Test response when get_project_highlights_by_project_id returns 404.""" project_id = 7362 new_highlight_description = 'new description of something' update_project_message = { 'project_id': project_id, 'thing': 'place'} update_project_data = update_project_message.copy() create_highlight_message = { 'attachment': 'N', 'client': 'alw', 'highlight_id': 12345, 'entity': 'project', 'mkt_program_id': 20, 'scope': 'public', 'description': new_highlight_description, 'entity_id': project_id, 'subject': 'Project Highlights'} user = 'alw:123' update_project_data['project_highlights'] = new_highlight_description mock_get_project_by_id.return_value = response.Response(message={}) mock_get_highlight_model.return_value = response.Response( message={}, status=404) mock_create_highlight_model.return_value = response.Response( message=create_highlight_message, status=201) mock_update_project.return_value = response.Response( message=update_project_message) result = project_manager.update_project( None, None, project_id, update_project_data, user) mock_get_highlight_model.assert_called_once_with(project_id) mock_update_highlight_model.assert_not_called() mock_create_highlight_model.assert_called_once_with( project_id, new_highlight_description) assert result.status == 200 assert result.message.get( 'project_highlights') == new_highlight_description @patch('project_manager.models.persister.get_project_by_id') @patch('project_manager.models.persister.update_project_by_id') @patch( 'project_manager.models.ows_marketing.update_project_highlights') @patch( 'project_manager.models.ows_marketing.get_project_highlights_by_project_id') # noqa def test_update_project_when_auth_fail( mock_get_highlight_model, mock_update_highlight_model, mock_update_project, mock_get_project_by_id): """Test response when authorization check fails.""" project_id = 7362 update_project_data = { 'project_id': project_id, 'thing': 'place', 'project_highlights': 'something'} mock_get_project_by_id.return_value = response.Response(status=403) result = project_manager.update_project( 'vendor', 2732, project_id, update_project_data, None) mock_get_highlight_model.assert_not_called() mock_update_highlight_model.assert_not_called() mock_update_project.assert_not_called() assert result.status == 403 def test_get_projects(db_fixture): """Assert getting projects for a vendor.""" vendor_id = 7123 subaccount_id = None page_offset = 0 page_limit = 100 logic_response = project_manager.get_projects( vendor_id, subaccount_id, page_offset, page_limit) assert logic_response.status == 200 for project in logic_response.message['items']: assert project['vendor_id'] == vendor_id def test_get_projects_for_subaccount(mocker, db_fixture): """Assert getting projects for a vendor.""" mocker.patch.object( ows_account, 'is_subaccount_for_vendor', return_value=response.Response( status=200, message='subaccount belongs to vendor')) vendor_id = 7123 subaccount_id = 2 page_offset = 0 page_limit = 100 logic_response = project_manager.get_projects( vendor_id, subaccount_id, page_offset, page_limit) assert logic_response.status == 200 for project in logic_response.message['items']: assert project['vendor_id'] == vendor_id assert project['subaccount_id'] == subaccount_id def test_get_projects_for_invalid_subaccount(mocker, db_fixture): """Assert getting projects for a vendor.""" mocker.patch.object( ows_account, 'is_subaccount_for_vendor', return_value=response.Response( status=403, message='subaccount does not belong to vendor')) vendor_id = 7123 subaccount_id = 1234 page_offset = 0 page_limit = 100 logic_response = project_manager.get_projects( vendor_id, subaccount_id, page_offset, page_limit) assert logic_response.status == 403 assert logic_response.message == 'subaccount does not belong to vendor' def test_get_project_by_project_code(mocker): """Assert that project_by_project_code calls the persister.""" expected_message = 'test message' mocker.patch.object( persister, 'get_project_by_project_code', return_value=response.Response(expected_message)) project_code = 'some_project_code' project_response = project_manager.get_project_by_project_code( 33188, 0, project_code) assert project_response assert project_response.message == expected_message def test_get_available_project_codes(mocker): """Assert that get_available_project_codes returns correctly.""" existing_projects = [ { 'project_id': 1, 'project_code': 'ABC', 'project_name': 'new project', 'artist_name': 'Test Artist 1' }, { 'project_id': 2, 'project_code': 'DEF', 'project_name': 'new project 2', 'artist_name': 'Test Artist 2' } ] mocker.patch.object( persister, 'get_existing_projects', return_value=response.Response(existing_projects)) project_codes = ['ABC', 'DEF', 'GHI'] project_response = project_manager.get_available_project_codes( 33188, 0, project_codes) assert project_response expected_response = { 'available_project_codes': ['GHI'], 'existing_projects': existing_projects, } assert project_response.message == expected_response def test_delete_project_when_project_has_products( test_request_context, mocker, get_company_brand, mock_vendor_data): """Assert delete not called and error if no products exist for project.""" mocker.patch.object( project_manager, '_get_project', return_value=response.Response( message={ 'vendor_id': 7123, }, ), ) mock_products = [{'product_id': 1}, {'product_id': 2}] mock_product_response = response.Response(message=mock_products) mocker.patch.object( persister, 'get_products_for_project', return_value=mock_product_response) mocker.patch.object( project_model, 'delete_project', return_value=response.Response()) mocker.patch.object( ows_account, 'get_vendor_company_brand', return_value=get_company_brand) mocker.patch.object( ows_account, 'get_vendor', return_value=mock_vendor_data) mocker.patch.object( pythonfeatures, 'get_single_feature', return_value=response.Response(message='disabled')) logic_response = project_manager.delete_project(1, 'vendor', 123) assert logic_response.status == 400 project_model.delete_project.assert_not_called() def test_delete_project_when_model_layer_error( test_request_context, mocker, get_company_brand, mock_vendor_data): """Assert error returned if delete project fails in model layer.""" mocker.patch.object( project_manager, '_get_project', return_value=response.Response( message={ 'vendor_id': 7123, }, ), ) mocker.patch.object( persister, 'get_products_for_project', return_value=response.Response(message=[])) mocker.patch.object( project_model, 'delete_project', return_value=response.create_fatal_response()) mocker.patch.object( ows_account, 'get_vendor_company_brand', return_value=get_company_brand) mocker.patch.object( ows_account, 'get_vendor', return_value=mock_vendor_data) mocker.patch.object( pythonfeatures, 'get_single_feature', return_value=response.Response(message='disabled')) logic_response = project_manager.delete_project(1, 'vendor', 123) assert logic_response.status == 500 def test_delete_project_when_project_has_no_products( test_request_context, mocker, get_company_brand, mock_vendor_data): """Assert delete called and success if no products exist for project.""" project_id = 1 mocker.patch.object( project_manager, '_get_project', return_value=response.Response( message={ 'vendor_id': 7123, }, ), ) mocker.patch.object( persister, 'get_products_for_project', return_value=response.Response(message=[])) get_highlight_response = response.Response(message={'highlight_id': 1123}) mocker.patch.object( ows_marketing, 'get_project_highlights_by_project_id', return_value=get_highlight_response) mocker.patch.object( ows_marketing, 'delete_project_highlight_with_project_deletion', return_value=response.Response()) mocker.patch.object( ows_account, 'get_vendor_company_brand', return_value=get_company_brand) mocker.patch.object( ows_account, 'get_vendor', return_value=mock_vendor_data) mocker.patch.object( project_model, 'delete_project', return_value=response.Response()) mocker.patch.object( pythonfeatures, 'get_single_feature', return_value=response.Response(message='disabled')) logic_response = project_manager.delete_project( project_id, 'vendor,', 123) assert logic_response.status == 200 project_model.delete_project.assert_called_with(project_id) def test_successful_delete_project_when_delete_highlight_fails( test_request_context, mocker, get_company_brand, mock_vendor_data): """Assert delete called and success when delete highlight fails.""" project_id = 1 mocker.patch.object( project_manager, '_get_project', return_value=response.Response( message={ 'vendor_id': 7123, }, ), ) mock_product_response = response.Response(message=[]) mocker.patch.object( persister, 'get_products_for_project', return_value=mock_product_response) get_highlight_response = response.Response(message={'highlight_id': 1123}) mocker.patch.object( ows_marketing, 'get_project_highlights_by_project_id', return_value=get_highlight_response) mocker.patch.object( ows_marketing, 'delete_project_highlight_with_project_deletion', return_value=response.create_fatal_response()) mocker.patch.object( project_model, 'delete_project', return_value=response.Response()) mocker.patch.object( ows_account, 'get_vendor_company_brand', return_value=get_company_brand) mocker.patch.object( ows_account, 'get_vendor', return_value=mock_vendor_data) mocker.patch.object( pythonfeatures, 'get_single_feature', return_value=response.Response(message='disabled')) logic_response = project_manager.delete_project( project_id, 'vendor,', 123) assert logic_response.status == 200 project_model.delete_project.assert_called_with(project_id) def test_delete_project_when_project_not_owned_by_account( test_request_context, mocker): """Assert that delete not called and forbidden error if ownership fail.""" mock_ownership_response = response.create_error_response( code=error_const.ERROR_CODE_AUTHORIZATION, message=error_const.ERROR_MESSAGE_FORBIDDEN_USER, status=http_status_codes.FORBIDDEN) mocker.patch.object( project_manager, '_get_project', return_value=mock_ownership_response) mocker.patch.object( project_model, 'delete_project', return_value=response.Response()) mocker.patch.object( pythonfeatures, 'get_single_feature', return_value=response.Response(message='disabled')) logic_response = project_manager.delete_project(1, 'vendor', 123) assert logic_response.status == 403 project_model.delete_project.assert_not_called() def test_delete_project_with_deletions_ff( test_request_context, mocker, get_company_brand, mock_vendor_data): """Assert delete called with deletions ff enabled.""" project_id = 1 mocker.patch.object( project_manager, '_get_project', return_value=response.Response( message={ 'vendor_id': 7123, }, ), ) mocker.patch.object( persister, 'get_products_for_project', return_value=response.Response(message=[])) mocker.patch.object( ows_marketing, 'get_project_highlights_by_project_id', return_value=None) mocker.patch.object( project_model, 'delete_project', return_value=response.Response()) mocker.patch.object( ows_account, 'get_vendor_company_brand', return_value=get_company_brand) mocker.patch.object( ows_account, 'get_vendor', return_value=mock_vendor_data) mocker.patch.object( pythonfeatures, 'get_single_feature', return_value=response.Response(message='disabled')) logic_response = project_manager.delete_project( project_id, 'vendor,', 123) assert logic_response.status == 200 project_model.delete_project.assert_called_with(project_id) @patch('project_manager.models.persister.get_project_by_id') @patch('project_manager.models.persister.update_project_by_id') @patch( 'project_manager.models.ows_marketing.update_project_highlights') @patch( 'project_manager.models.ows_marketing.get_project_highlights_by_project_id') # noqa def test_update_project_with_orchard_user_id( mock_get_highlight_model, mock_update_highlight_model, mock_update_project, mock_get_project_by_id): """Update a project while returning current highlights if not provided.""" project_highlights = 'Some project highlight' project_id = 7362 update_project_data = { 'project_id': project_id, 'project_name': 'new name', 'artist_id': 12345, 'description': 'new description' } get_highlight_message = { 'attachment': 'N', 'client': 'alw', 'highlight_id': 2763, 'entity': 'project', 'mkt_program_id': 20, 'scope': 'public', 'description': project_highlights, 'entity_id': project_id, 'subject': 'Project Highlights' } update_project_message = {'updated_date_utc': '000.000.000'} update_project_message.update(update_project_data.copy()) mock_get_project_by_id.return_value = response.Response(message={}) mock_update_project.return_value = response.Response( message=update_project_message) mock_get_highlight_model.return_value = response.Response( message=get_highlight_message) user = 'alw:123' result = project_manager.update_project( None, None, project_id, update_project_data, user) expected_message = update_project_message.copy() expected_message['project_highlights'] = project_highlights mock_get_highlight_model.assert_called_once_with(project_id) mock_update_highlight_model.assert_not_called() assert result.message == expected_message @patch('project_manager.models.persister.get_project_by_id') @patch('project_manager.models.persister.update_project_by_id') @patch( 'project_manager.models.ows_marketing.update_project_highlights') @patch( 'project_manager.models.ows_marketing.get_project_highlights_by_project_id') # noqa def test_update_project_when_orchard_user_id_missing( mock_get_highlight_model, mock_update_highlight_model, mock_update_project, mock_get_project_by_id): """Test response when orchard_user_id is missing.""" project_id = 7362 update_project_data = { 'project_id': project_id, 'thing': 'place', 'project_highlights': 'something' } mock_get_project_by_id.return_value = response.Response(message={}) result = project_manager.update_project( 'vendor', 2732, project_id, update_project_data, None) assert result.status == 400 assert result.errors['message'] == \ error_const.ERROR_MESSAGE_MISSING_ORCHARD_USER_ID assert result.errors['code'] == \ error_const.ERROR_CODE_MISSING_ORCHARD_USER_ID def test_set_mkt_priority_for_project(mocker, db_fixture): """Assert setting mkt_priority_project for a project.""" project_id = 1 country_id = 1 priority = 'a' mkt_priority_obj = { 'project_id': project_id, 'country_id': country_id, 'priority': priority } mocker.patch.object( mkt_priority, 'set_mkt_priority_by_project_id', return_value=response.Response( status=200, message=mkt_priority_obj)) logic_response = project_manager.set_mkt_priority( project_id, country_id, priority, 1) assert logic_response.status == 200 assert logic_response.message == mkt_priority_obj def test_get_mkt_priority_for_project(mocker, db_fixture): """Assert get mkt_priority_project for a project.""" project_id = 1 country_id = 1 priority = 'a' mkt_id = 12 mkt_priority_obj = [{ 'id': mkt_id, 'project_id': project_id, 'country_id': country_id, 'priority': priority }] mocker.patch.object( mkt_priority, 'get_mkt_priority_by_project_id', return_value=response.Response( status=200, message=mkt_priority_obj)) logic_response = project_manager.get_mkt_priority(project_id) assert logic_response.status == 200 assert logic_response.message == {'mkt_priority': mkt_priority_obj} def test_get_bulk_mkt_priority(mocker, db_fixture): """Assert get_bulk_mkt_priority for projects works as expected.""" project_ids = [1, 2, 3] country_id = 1 priority = 'a' mkt_id = 12 mkt_priority_obj = [ { 'id': mkt_id, 'project_id': 1, 'country_id': country_id, 'priority': priority }, { 'id': mkt_id + 1, 'project_id': 2, 'country_id': country_id + 1, 'priority': priority }, { 'id': mkt_id + 2, 'project_id': 3, 'country_id': country_id + 2, 'priority': priority }, ] mocker.patch.object( mkt_priority, 'get_bulk_mkt_priority_by_project_ids', return_value=response.Response( status=200, message=mkt_priority_obj)) logic_response = project_manager.get_bulk_mkt_priority(project_ids) assert logic_response.status == 200 assert logic_response.message == {'mkt_priority': mkt_priority_obj} def test_delete_mkt_priority_for_project(mocker, db_fixture): """Assert deleting mkt_priority_project for a project.""" project_id = 1 projection_id = 1 mocker.patch.object( mkt_priority, 'delete_mkt_priority_by_project_id', return_value=response.Response( status=200)) logic_response = project_manager.delete_mkt_priority(project_id, projection_id) assert logic_response.status == 200 def test_bulk_delete_mkt_priority_for_project(mocker, db_fixture): """Assert deleting mkt_priority_project for a project in bulk.""" project_id = 1 mocker.patch.object( mkt_priority, 'bulk_delete_mkt_priority_for_project', return_value=response.Response( status=200)) logic_response = project_manager.bulk_delete_mkt_priority_for_project( project_id) assert logic_response.status == 200