"""Test for asset_info logic module.""" import datetime from typing import Any import pytest from flexmock import flexmock from sqlalchemy.exc import SQLAlchemyError from assets.constants import api, field_const from assets.constants.asset_upload_types import STEREO from assets.constants.error import ERROR_ASSET_FINAL_NOT_FOUND from assets.exceptions import AssetFinalNotFound, NoAssetsFound from assets.logic import asset_info from assets.models import asset_final, asset_upload, asset_upload_type, s3_file @pytest.fixture def fixture_asset_info_raw_file_args() -> dict[str, Any]: """Call args for raw file call.""" return { field_const.FILENAME: "unique_raw_filename.ext", field_const.STATE: field_const.ASSET_STATE_RAW, } @pytest.fixture def fixture_asset_info_final_file_args() -> dict[str, Any]: """Call args for final file call.""" return { field_const.FILENAME: "unique_final_filename.ext", field_const.STATE: field_const.ASSET_STATE_FINAL, } @pytest.fixture def fixture_asset_info_by_id_args() -> dict[str, Any]: """Call args for asset info by id call.""" return { field_const.ASSET_FINAL_ID: 2, } @pytest.fixture def fixture_get_asset_upload_response() -> dict[str, Any]: """Return mock for get_asset_upload.""" return { "id": 10001, "user_id": "oa:12345", "token": "secret_token", "filename": "unique_raw_filename", "product_id": 0, "upc": 321, "track_unique_id": 1, "asset_upload_type_id": 1, } @pytest.fixture def fixture_get_single_asset_upload_response() -> list[dict[str, Any]]: """Return mock for get_asset_upload.""" return [ { "id": 10001, "user_id": "oa:12345", "token": "secret_token", "filename": "unique_raw_filename", "product_id": 123, "upc": 321, "track_unique_id": 1, "updated_timestamp": datetime.datetime(2022, 12, 28, 23, 55, 59, 342380), } ] @pytest.fixture def fixture_get_single_asset_upload_wav_response() -> list[dict[str, Any]]: """Return mock for get_asset_upload.""" return [ { "id": 10001, "user_id": "oa:12345", "token": "secret_token", "filename": "unique_raw_filename", "product_id": 123, "upc": 321, "track_unique_id": 1, "updated_timestamp": datetime.datetime(2022, 12, 28, 23, 55, 59, 342380), } ] @pytest.fixture def fixture_get_asset_final_mp3_response_by_asset_upload_ids() -> dict[ int, list[dict[str, Any]] ]: """Return mock for get_asset_final.""" return { 10001: [ { "id": 1, "asset_upload_id": 10001, "asset_subtype": "none", "bucket": "some_bucket", "filename": "filename_1.mp3", "duration": 45000, } ], 10002: [ { "id": 2, "asset_upload_id": 10002, "asset_subtype": "none", "bucket": "some_bucket", "filename": "filename_2.mp3", "duration": 45000, } ], } @pytest.fixture def fixture_get_asset_final_response_by_asset_upload_ids() -> dict[ int, list[dict[str, Any]] ]: """Return mock for get_asset_final.""" return { 10001: [ { "id": 1, "asset_upload_id": 10001, "asset_subtype": "none", "bucket": "some_bucket", "filename": "filename_1.wav", "duration": 45000, } ], 10002: [ { "id": 2, "asset_upload_id": 10002, "asset_subtype": "none", "bucket": "some_bucket", "filename": "filename_2.wav", "duration": 45000, } ], } @pytest.fixture def fixture_get_asset_final_response() -> dict[str, Any]: """Return mock for get_asset_final.""" return { "id": 101, "asset_upload_id": 10, "bucket": "some_final_bucket", "filename": "unique_final_filename.ext", "duration": 45000, } @pytest.mark.parametrize("filename", ["unique_raw_filename.ext", "unique_raw_filename"]) def test_get_asset_info_raw_file_success( fixture_asset_info_raw_file_args: dict[str, Any], fixture_get_asset_upload_response: dict[str, Any], filename: str, ) -> None: """Test for success of get_asset_info for raw file.""" fixture_asset_info_raw_file_args[field_const.FILENAME] = filename ( flexmock(asset_upload) .should_receive("get_asset_upload") .with_args(filename="unique_raw_filename", api_version=api.API_VERSION_V2) .and_return(fixture_get_asset_upload_response) ) ( flexmock(asset_upload_type) .should_receive("resolve_asset_upload_type") .with_args( asset_upload_type_id=fixture_get_asset_upload_response[ field_const.ASSET_UPLOAD_TYPE_ID ] ) .and_return(STEREO) ) result = asset_info.get_asset_info(**fixture_asset_info_raw_file_args) assert result[field_const.FILENAME] == "unique_raw_filename" assert result[field_const.ASSET_UPLOAD_TYPE] == STEREO def test_get_asset_info_raw_file_failure( fixture_asset_info_raw_file_args: dict[str, Any], ) -> None: """Test for failure of get_asset_info for raw file.""" error_message = "Query error" ( flexmock(asset_upload) .should_receive("get_asset_upload") .and_raise(SQLAlchemyError(error_message)) ) with pytest.raises(SQLAlchemyError) as exc: asset_info.get_asset_info(**fixture_asset_info_raw_file_args) assert str(exc.value) == error_message def test_get_asset_info_final_file_success( fixture_asset_info_final_file_args: dict[str, Any], fixture_get_asset_final_response: dict[str, Any], fixture_get_asset_upload_response: dict[str, Any], ) -> None: """Test for success of get_asset_info for final file.""" raw_filename = fixture_get_asset_upload_response[field_const.FILENAME] ( flexmock(asset_final) .should_receive("get_asset_final") .and_return(fixture_get_asset_final_response) ) ( flexmock(asset_upload) .should_receive("get_asset_upload_by_id") .and_return(fixture_get_asset_upload_response) ) ( flexmock(asset_upload_type) .should_receive("resolve_asset_upload_type") .with_args( asset_upload_type_id=fixture_get_asset_upload_response[ field_const.ASSET_UPLOAD_TYPE_ID ] ) .and_return(STEREO) ) result = asset_info.get_asset_info(**fixture_asset_info_final_file_args) assert result[field_const.FILENAME] == raw_filename assert result[field_const.ASSET_UPLOAD_TYPE] == STEREO @pytest.fixture def get_final_asset_info_mocks( fixture_get_asset_final_response: dict[str, Any], fixture_get_asset_upload_response: dict[str, Any], ) -> dict[str, Any]: """Return mocks for get_asset_info.""" return { "get_asset_final": fixture_get_asset_final_response, "get_asset_final_by_id": fixture_get_asset_final_response, "get_asset_upload_by_id": fixture_get_asset_upload_response, } def test_get_asset_info_final_file_asset_final_failure( fixture_asset_info_final_file_args: dict[str, Any], get_final_asset_info_mocks: dict[str, Any], ) -> None: """Test for failure of get_asset_info for final file.""" error_message = "Query error" ( flexmock(asset_final) .should_receive("get_asset_final") .and_raise(SQLAlchemyError(error_message)) ) with pytest.raises(SQLAlchemyError) as exc: asset_info.get_asset_info(**fixture_asset_info_final_file_args) assert str(exc.value) == error_message def test_get_asset_info_final_file_asset_upload_failure( fixture_asset_info_final_file_args: dict[str, Any], get_final_asset_info_mocks: dict[str, Any], ) -> None: """Test for failure of get_asset_info for final file.""" error_message = "Query error" ( flexmock(asset_final) .should_receive("get_asset_final") .and_return(get_final_asset_info_mocks["get_asset_final"]) ) ( flexmock(asset_upload) .should_receive("get_asset_upload_by_id") .and_raise(SQLAlchemyError(error_message)) ) with pytest.raises(SQLAlchemyError) as exc: asset_info.get_asset_info(**fixture_asset_info_final_file_args) assert str(exc.value) == error_message def test_get_v2_assets_info_by_asset_type_mp3_success( fixture_get_single_asset_upload_response: list[dict[str, Any]], fixture_get_asset_final_mp3_response_by_asset_upload_ids: list[dict[str, Any]], ) -> None: """Test success of get_v2_assets_info_by_asset_type.""" product_id = 123 asset_type = "MP3_192" track_id = 1 flexmock(asset_upload).should_receive("get_latest_asset_upload").and_return( fixture_get_single_asset_upload_response ) flexmock(asset_final).should_receive( "get_asset_final_by_asset_upload_ids" ).and_return(fixture_get_asset_final_mp3_response_by_asset_upload_ids) expected_result = { "product_id": product_id, "assets": [ { "filename": "filename_1.mp3", "bucket": "some_bucket", "track_unique_id": 1, "updated_timestamp": "2022-12-28 23:55:59", } ], } assert ( asset_info.get_v2_assets_info_by_asset_type(product_id, asset_type, track_id) == expected_result ) def test_get_v2_assets_info_by_asset_type_wav_success( fixture_get_single_asset_upload_wav_response: list[dict[str, Any]], fixture_get_asset_final_response_by_asset_upload_ids: list[dict[str, Any]], ) -> None: """Test success of get_v2_assets_info_by_asset_type.""" product_id = 123 asset_type = "WAV" track_id = 1 flexmock(asset_upload).should_receive("get_latest_asset_upload").and_return( fixture_get_single_asset_upload_wav_response ) flexmock(asset_final).should_receive( "get_asset_final_by_asset_upload_ids" ).and_return(fixture_get_asset_final_response_by_asset_upload_ids) expected_result = { "product_id": product_id, "assets": [ { "filename": "filename_1.wav", "bucket": "some_bucket", "track_unique_id": 1, "updated_timestamp": "2022-12-28 23:55:59", } ], } assert ( asset_info.get_v2_assets_info_by_asset_type(product_id, asset_type, track_id) == expected_result ) def test_get_asset_download_url_by_id_success( fixture_get_asset_final_response: dict[str, Any], ) -> None: """Test for success of get_asset_download_url_by_id.""" asset_final_id = 123 expires_in = 17 expected_url = "https://signed_url/somefile.ext" ( flexmock(asset_final) .should_receive("get_asset_final_by_id") .with_args(asset_final_id) .and_return(fixture_get_asset_final_response) ) ( flexmock(s3_file) .should_receive("check_s3_file_exists") .with_args( fixture_get_asset_final_response["bucket"], fixture_get_asset_final_response["filename"], ) .and_return(True) ) ( flexmock(s3_file) .should_receive("create_presigned_url") .with_args( fixture_get_asset_final_response["bucket"], fixture_get_asset_final_response["filename"], expires_in, ) .and_return(expected_url) ) result = asset_info.get_asset_download_url_by_id(asset_final_id, expires_in) assert result["url"] == expected_url def test_get_asset_download_url_by_id_not_found_id() -> None: """Test asset not in database.""" asset_final_id = 123 ( flexmock(asset_final) .should_receive("get_asset_final_by_id") .with_args(asset_final_id) .and_raise(AssetFinalNotFound(ERROR_ASSET_FINAL_NOT_FOUND)) ) (flexmock(s3_file).should_receive("check_s3_file_exists").never()) (flexmock(s3_file).should_receive("create_presigned_url").never()) with pytest.raises(AssetFinalNotFound) as exc: asset_info.get_asset_download_url_by_id(asset_final_id, 17) assert exc.value.description == ERROR_ASSET_FINAL_NOT_FOUND def test_get_asset_download_url_by_id_not_found_object( fixture_get_asset_final_response: dict[str, Any], ) -> None: """Test asset not in s3.""" asset_final_id = 123 ( flexmock(asset_final) .should_receive("get_asset_final_by_id") .with_args(asset_final_id) .and_return(fixture_get_asset_final_response) ) ( flexmock(s3_file) .should_receive("check_s3_file_exists") .with_args( fixture_get_asset_final_response["bucket"], fixture_get_asset_final_response["filename"], ) .and_return(False) ) (flexmock(s3_file).should_receive("create_presigned_url").never()) with pytest.raises(NoAssetsFound) as exc: asset_info.get_asset_download_url_by_id(asset_final_id, 17) assert ( exc.value.description == f"{fixture_get_asset_final_response['filename']} not found in S3" ) def test_get_asset_info_by_id_success( fixture_asset_info_by_id_args: dict[str, Any], fixture_get_asset_final_response: dict[str, Any], fixture_get_asset_upload_response: dict[str, Any], ) -> None: """Test for success of get_asset_info_by_id for final file.""" raw_filename = fixture_get_asset_upload_response[field_const.FILENAME] ( flexmock(asset_final) .should_receive("get_asset_final_by_id") .and_return(fixture_get_asset_final_response) ) ( flexmock(asset_upload) .should_receive("get_asset_upload_by_id") .and_return(fixture_get_asset_upload_response) ) result = asset_info.get_asset_info_by_id(**fixture_asset_info_by_id_args) assert result[field_const.FILENAME] == raw_filename assert result[field_const.PRODUCT_ID] == 0 assert result[field_const.DURATION] == 45000 def test_get_asset_info_by_id_failure( fixture_asset_info_by_id_args: dict[str, Any], get_final_asset_info_mocks: dict[str, Any], ) -> None: """Test for failure of get_asset_info_by_id for final file.""" ( flexmock(asset_final) .should_receive("get_asset_final_by_id") .and_raise(SQLAlchemyError("fatal error")) ) with pytest.raises(SQLAlchemyError) as exc: asset_info.get_asset_info_by_id(**fixture_asset_info_by_id_args) assert str(exc.value) == "fatal error" def test_get_asset_info_by_id_asset_upload_failure( get_final_asset_info_mocks: dict[str, Any], fixture_asset_info_by_id_args: dict[str, Any], ) -> None: """Test for failure of get_asset_info_by_id for final file.""" error_message = "Query error" ( flexmock(asset_final) .should_receive("get_asset_final_by_id") .and_return(get_final_asset_info_mocks["get_asset_final_by_id"]) ) ( flexmock(asset_upload) .should_receive("get_asset_upload_by_id") .and_raise(SQLAlchemyError(error_message)) ) with pytest.raises(SQLAlchemyError) as exc: asset_info.get_asset_info_by_id(**fixture_asset_info_by_id_args) assert str(exc.value) == error_message