"""Functional tests for post product handler.""" import json from unittest.mock import MagicMock from flexmock import flexmock from oto import response import pytest from product_digital import features from product_digital.connectors import mysql from product_digital.constants import features as feature_names from product_digital.constants import header from product_digital.logic import product from product_digital.models import audio_product from product_digital.models import ows_product_workflow from product_digital.models import project from product_digital.models import release from product_digital.models import release_artist from product_digital.models import release_subgenre from tests.testutils import db COPY_ENDPOINT_PATH = 'product/{}/copy' @pytest.fixture def cr_rejections_ff_disabled(): """Mock out validation calls for complete product.""" ( flexmock(features) .should_receive('is_feature_flag_enabled') .with_args( feature_names.REJECTIONS_FROM_CONTENTREVIEW, use_account_context=True ) .and_return(False) ) def get_release_count(): """Query the db and count Release entries. Returns: int: Release count """ with mysql.db_session() as session: return session.query(release.Release).count() def setup_test_post_copy_product(mocker, base_release_data): """Helper function to mock dependencies and setup test cases.""" mocker.patch.object( features, 'is_rejections_from_content_review_enabled', return_value=False) mocker.patch.object( release_artist, 'get_release_artists_by_release_id', return_value=response.Response(message=[])) mocker.patch.object( release_subgenre, 'get_release_subgenre_by_release_id', return_value=None) project_data = { 'vendor_id': 9999, 'project_name': 'Test project', 'project_id': base_release_data['project_id'], 'project_code': base_release_data['vendor_catalog_number'], 'artist_id': base_release_data['artist_id'], } expected_project_id = project_data['project_id'] (flexmock(project) .should_receive('get_project_by_id') .with_args(expected_project_id) .and_return(response.Response(message=project_data))) product_data = {} product_data.update(base_release_data) new_release = audio_product.create(product_data) new_release_id = new_release.message['product_id'] mock_response = MagicMock(status_code=200, message=None) mocker.patch.object( ows_product_workflow, 'get_last_release_approval_queue', return_value=mock_response) new_release_data = product.get_audio_product(new_release_id) return new_release_data.message def _test_copied_fields(old_data, new_data, product_basics): """Test field value for copied product. Args: old_data (dict): audio_product.get_product() response for the original product new_data (dict): audio_product.get_product() response for the product copy product_basics (dict): values that should be changed """ excluded_fields = ( 'product_id', # this is the 'release_id' field on the model 'upc', 'display_upc', 'product_code', 'format', 'version', 'release_approval_status' ) for field_name, expected_value in old_data.items(): # catalog_transfer_info is GET-only for now, not part of the copy # response contract. if field_name == 'catalog_transfer_info': continue new_value = new_data[field_name] # if field is in the exclded fields - ensure that it is not the same if field_name in excluded_fields: assert new_value != expected_value # if field is in product basics - ensure that it was updated elif field_name in product_basics: expected_value = product_basics[field_name] assert new_value == expected_value # in all other cases - make sure that the value is copied else: assert new_value == expected_value @pytest.mark.parametrize('on_create_state, on_update_state', [ (True, True), ]) @db.test_schema def test_post_copy_product( client, valid_headers, copy_product_basics, mocker, expected_product_payload, base_product_data_with_vendor, get_upc, mock_check_project, validate_product_on_create, validate_product_on_update, cr_rejections_ff_disabled): """Test result when posting as a microservice.""" subaccount_id = 42 expected_product_payload['subaccount_id'] = subaccount_id existing_release_data = setup_test_post_copy_product( mocker, expected_product_payload) assert get_release_count() == 1 url = COPY_ENDPOINT_PATH.format(existing_release_data['product_id']) client_response = client.post( url, headers=valid_headers, data=json.dumps(copy_product_basics)) response_json = json.loads(client_response.data.decode('utf-8')) assert client_response.status_code == 201 assert get_release_count() == 2 assert response_json['subaccount_id'] == subaccount_id _test_copied_fields( existing_release_data, response_json, copy_product_basics) @pytest.mark.parametrize('on_create_state, on_update_state', [ (True, True), ]) @db.test_schema def test_post_copy_product_no_upc_in_request_body( client, valid_headers, copy_product_basics, mocker, expected_product_payload, base_product_data_with_vendor, get_upc, mock_check_project, validate_product_on_create, validate_product_on_update, cr_rejections_ff_disabled): """Test result when posting as a microservice. Test result when ownership, upc_available, and get_project all succeed. """ existing_release_data = setup_test_post_copy_product( mocker, expected_product_payload) assert get_release_count() == 1 copy_product_basics['upc'] = None mocker.patch.object( product, '_return_upc_value_and_update_status', return_value='123456789015') url = COPY_ENDPOINT_PATH.format(existing_release_data['product_id']) client_response = client.post( url, headers=valid_headers, data=json.dumps(copy_product_basics)) response_json = json.loads(client_response.data.decode('utf-8')) assert client_response.status_code == 201 assert get_release_count() == 2 _test_copied_fields( existing_release_data, response_json, copy_product_basics) @pytest.mark.parametrize('grass_headers', [ {header.GRASS_ACCOUNT_ID: 1234, header.GRASS_ACCOUNT_TYPE: 'subaccount'}, {header.GRASS_ACCOUNT_ID: 1234}, {header.GRASS_ACCOUNT_TYPE: 'subaccount'}, ]) @db.test_schema def test_post_copy_product_grass_headers_fails( client, valid_headers, copy_product_basics, grass_headers, mocker, expected_product_payload, base_product_data_with_vendor, get_upc, mock_check_project, validate_product_on_create, validate_product_on_update, cr_rejections_ff_disabled): """Test result when posting as a microservice. Test result when ownership, upc_available, and get_project all succeed. """ existing_release_data = setup_test_post_copy_product( mocker, expected_product_payload) assert get_release_count() == 1 url = COPY_ENDPOINT_PATH.format(existing_release_data['product_id']) grass_headers.update(valid_headers) client_response = client.post( url, headers=grass_headers, data=json.dumps(copy_product_basics)) assert client_response.status_code == 400 assert get_release_count() == 1