"""Tests for ows-assets model.""" import json from oto import response from oto import status as response_code import pytest from requests import Response from backend.constants import error from backend.constants import header from backend.exceptions import RequestError from backend.models import ows_assets @pytest.fixture def product_assets_v1_payload(): """Payload returned from GET ows-assets/assets/product/.""" payload = { 'product_id': 1, 'upc': 'the upc', 'assets': [{ 'filename': 'unique_filename_2', 'asset_type': '', 'status': 'finished', 'track_unique_id': 111, 'stream': { 'track_unique_id': 111, 'url': 'rtmp://prefix/1/wav/100075/100075236325_2232323232', 'duration': 10.813 }, 'original_filename': 'original_filename_2' }] } return payload @pytest.fixture def product_assets_v2_payload(): """Payload returned from GET ows-assets/v2/assets/product/.""" payload = { 'product_id': 1, 'upc': 'the upc', 'assets': [{ 'filename': 'unique_filename_2', 'asset_type': '', 'status': 'finished', 'track_unique_id': 111, 'stream': { 'track_unique_id': 111, 'url': 'rtmp://prefix/1/wav/100075/100075236325_2232323232', 'duration': 10.813 }, 'original_filename': 'original_filename_2' }] } return payload @pytest.fixture def product_assets_v1_payload_with_correction(): """Payload returned from GET ows-assets/assets/product/.""" payload = { 'product_id': 1, 'upc': 'the upc', 'assets': [{ 'filename': 'unique_filename_2', 'asset_type': '', 'status': 'finished', 'track_unique_id': 111, 'stream': { 'track_unique_id': 111, 'url': 'rtmp://prefix/1/wav/100075/100075236325_2232323232', 'duration': 10.813 }, 'original_filename': 'original_filename_2', 'correction': { 'filename': 'unique_filename_3', 'asset_type': '', 'status': 'finished', 'track_unique_id': 111, 'stream': { 'track_unique_id': 111, 'url': 'rtmp://prefix/1/wav/100075/100075236325_2232323232', 'duration': 11.813 }, 'original_filename': 'original_filename_3' } }] } return payload def _mock_assets_request(method, status_code, payload, mocker): """Mock given method of owsrequest.request.""" mock_assets_response = Response() mock_assets_response._content = json.dumps(payload).encode('latin1') mock_assets_response.status_code = status_code mock_method = mocker.patch.object( ows_assets.request, method, return_value=mock_assets_response) return mock_method def test_copy_assets(mocker): """Test copy track assets from one tuid to another.""" ok_message = {'status': 'ok'} mock_request = _mock_assets_request( 'post', response_code.OK, ok_message, mocker) assets_response = ows_assets.copy_assets( from_tuid=1, to_tuid=2, orchard_user_id='alw:123', correlation_id='1a9') expected_body = { header.ORCHARD_USER_ID: 'alw:123' } mock_request.assert_called_with( 'ows-assets', '/track/1/copy/2', json=expected_body, correlation_id='1a9') assert isinstance(assets_response, response.Response) assert assets_response.status == response_code.OK assert assets_response.message == ok_message def test_copy_assets_error_response(mocker): """Test error response from ows-assets is handled.""" error_message = {'message': 'Product not found'} _mock_assets_request( 'post', response_code.NOT_FOUND, error_message, mocker) assets_response = ows_assets.copy_assets( from_tuid=1, to_tuid=2, orchard_user_id='alw:123', correlation_id='1a9') assert assets_response.status == response_code.NOT_FOUND expected_errors = { 'code': error.OWS_ASSETS_ERROR_CODE, 'message': error_message } assert assets_response.errors == expected_errors def test_delete_track_assets(mocker): """Should delete track assets.""" ok_message = {'status': 'ok'} mock_delete = _mock_assets_request( 'delete', response_code.OK, ok_message, mocker) assets_response = ows_assets.delete_track_assets(tuid=1) mock_delete.assert_called_with('ows-assets', '/track/1') assert isinstance(assets_response, response.Response) assert assets_response.status == response_code.OK def test_delete_track_assets_error_response(mocker): """Should handle error response from ows-assets.""" error_message = {'message': 'Track not found', 'code': 'non_found_error'} _mock_assets_request( 'delete', response_code.NOT_FOUND, error_message, mocker) assets_response = ows_assets.delete_track_assets(tuid=1) assert isinstance(assets_response, response.Response) assert assets_response.status == response_code.NOT_FOUND def test_bulk_delete_assets(mocker): """Should delete assets of multiple tracks.""" mock_delete_assets = mocker.patch.object( ows_assets, 'delete_track_assets', side_effects=[response.Response()] * 2) expected_calls = [mocker.call(1), mocker.call(2)] ows_assets.bulk_delete_track_assets(tuids=[1, 2]) mock_delete_assets.assert_has_calls(expected_calls) def test_get_product_assets_v2(mocker, product_assets_v2_payload): """Should get product assets by product_id.""" expected_payload = { 'items': [ {'track_unique_id': 111, 'status': 'finished', 'duration': 10813, 'asset_upload_type': None}], 'pagination': {'type': 'none', 'total_records': 1} } mock_get_assets = _mock_assets_request( 'get', 200, product_assets_v2_payload, mocker, ) expected_call_args = { 'service_name': 'ows-assets', 'path': '/v2/asset/product/1' } assets_response = ows_assets.get_product_assets_v2(product_id=1) mock_get_assets.assert_called_with(**expected_call_args) assert assets_response.status == response_code.OK assert assets_response.message == expected_payload def test_get_product_assets_v2_not_found(mocker): """Should handle case when product not found.""" mock_get_payload = { 'message': 'Product not found', 'code': 'not_found_error' } _mock_assets_request('get', 404, mock_get_payload, mocker) assets_response = ows_assets.get_product_assets_v2(product_id=1) assert assets_response.status == response_code.NOT_FOUND def test_get_product_assets_v2_server_error(mocker): """Should handle case when server error happened.""" mock_get_payload = { 'message': 'Something bad happened', 'code': 'server_error' } _mock_assets_request('get', 500, mock_get_payload, mocker) assets_response = ows_assets.get_product_assets_v2(product_id=1) assert assets_response.status == response_code.INTERNAL_ERROR def test_format_asset_dicts_v2(product_assets_v2_payload): """Expect to convert assets response to required format.""" expected_payload = [{ 'track_unique_id': 111, 'duration': 10813, 'status': 'finished', 'asset_upload_type': None }] result = ows_assets._format_asset_dicts_v2(product_assets_v2_payload) assert result == expected_payload def test_format_asset_dicts_v2_handles_empty_assets(product_assets_v2_payload): """Expect to handle empty assets list.""" product_assets_v2_payload['assets'] = [] assert ows_assets._format_asset_dicts_v2(product_assets_v2_payload) == [] def test_format_asset_dicts_v2_skips_non_audio_assets(product_assets_v2_payload): """Expect to ignore non-audio assets of product.""" product_assets_v2_payload['assets'][0]['track_unique_id'] = 0 assert ows_assets._format_asset_dicts_v2(product_assets_v2_payload) == [] @pytest.mark.parametrize('stream', [None, '', {}]) def test_format_assets_handles_upload_error_v2(stream): """Expect to handle asset with status == error.""" product_assets_payload = { 'product_id': 1, 'upc': 'the upc', 'assets': [{ 'filename': 'unique_filename_2', 'asset_type': '', 'status': 'error', 'track_unique_id': 111, 'original_filename': 'original_filename_2' }] } if stream is not None: product_assets_payload['assets'][0]['stream'] = stream expected_payload = [{ 'track_unique_id': 111, 'status': 'error', 'duration': None, 'asset_upload_type': None }] result = ows_assets._format_asset_dicts_v2(product_assets_payload) assert result == expected_payload def test_get_match_audio_results_success(mock_app, request_engine): """Test get_match_audio_results success.""" expected_result = ['item0', 'item1'] request_engine['ows-assets'].add_spec( 'GET', '/v2/asset/product/12321/match-audio', response={ 'items': expected_result } ) result = ows_assets.get_match_audio_results(12321) assert result == expected_result def test_get_match_audio_results_404_success(mock_app, request_engine): """Test get_match_audio_results 404 success.""" request_engine['ows-assets'].add_spec( 'GET', '/v2/asset/product/12321/match-audio', status=404 ) result = ows_assets.get_match_audio_results(12321) assert result == [] def test_get_match_audio_results_error(mock_app, request_engine): """Test get_match_audio_results error.""" request_engine['ows-assets'].add_spec( 'GET', '/v2/asset/product/12321/match-audio', status=500, response={'oopsies': 'something went wrong'} ) expected_message = ( 'Failed to get match audio results for product_id: 12321. ' 'Error: {"oopsies": "something went wrong"}' ) with pytest.raises(RequestError) as excinfo: ows_assets.get_match_audio_results(12321) assert excinfo.value == RequestError( expected_message, error_code='ows_assets_error', http_status=500 ) def test_get_ai_generated_audio_results_success(mock_app, request_engine): """Test get_ai_generated_audio_results success.""" expected_result = ['item0', 'item1'] request_engine['ows-assets'].add_spec( 'GET', '/v2/asset/product/12321/ai-generated-audio', response={ 'items': expected_result } ) result = ows_assets.get_ai_generated_audio_results(12321) assert result == expected_result def test_get_ai_generated_audio_results_404_success(mock_app, request_engine): """Test get_ai_generated_audio_results 404 returns empty list.""" request_engine['ows-assets'].add_spec( 'GET', '/v2/asset/product/12321/ai-generated-audio', status=404 ) result = ows_assets.get_ai_generated_audio_results(12321) assert result == [] def test_get_ai_generated_audio_results_error(mock_app, request_engine): """Test get_ai_generated_audio_results error handling.""" request_engine['ows-assets'].add_spec( 'GET', '/v2/asset/product/12321/ai-generated-audio', status=500, response={'error': 'internal server error'} ) expected_message = ( 'Failed to get suspected AI generated audio results for product_id: 12321. ' 'Error: {"error": "internal server error"}' ) with pytest.raises(RequestError) as excinfo: ows_assets.get_ai_generated_audio_results(12321) assert excinfo.value == RequestError( expected_message, error_code='ows_assets_error', http_status=500 )