"""Test for delete asset methods.""" from contextlib import contextmanager from typing import Any, Generator from unittest import mock from unittest.mock import MagicMock import pytest import pytest_mock from flexmock import flexmock from requests.exceptions import HTTPError from sqlalchemy.exc import SQLAlchemyError from syrupy.assertion import SnapshotAssertion from assets.connectors import mysql from assets.constants import ( api, asset_status as asset_status_constants, error as error_constants, product as product_constants, success as success_constants, ) from assets.exceptions import ( AssetDeleteFailure, AssetFinalNotFound, AssetStatusNotFound, AssetUploadNotFound, ErrorDiscardingCorrections, InvalidProductStatus, WrongAssetStatus, ) from assets.logic import delete from assets.models import ( asset_final, asset_status, asset_upload, asset_upload_type, ows_product, ows_track, s3_file, ) def mock_db_session(mocker: pytest_mock.MockerFixture, db_session: str) -> mock.Mock: """Create a mock database sesssion. Also mock the db_session context manager to use the mock session. """ mock_session = mock.Mock(query=mock.Mock()) @contextmanager def fake_session_manager() -> Generator[mock.Mock, None, None]: yield mock_session mocker.patch.object(mysql, db_session, fake_session_manager) return mock_session @pytest.fixture def fixture_assets_data() -> list[Any]: """Fixture to return assets data.""" return [ { "id": 1, "filename": "original_filename_1", "product_id": 1234, "track_unique_id": 10001, "deleted": 0, }, { "id": 2, "filename": "original_filename_2", "product_id": 1234, "track_unique_id": 10002, "deleted": 0, }, { "id": 3, "filename": "original_filename_3", "product_id": 1234, "track_unique_id": 10003, "deleted": 0, }, ] @pytest.fixture def fixture_assets_marked_deleted_data() -> list[Any]: """Fixture to return assets data marked deleted.""" return [ { "id": 1, "filename": "original_filename_1", "product_id": 1234, "track_unique_id": 10001, "deleted": 1, }, { "id": 2, "filename": "original_filename_2", "product_id": 1234, "track_unique_id": 10002, "deleted": 1, }, { "id": 3, "filename": "original_filename_3", "product_id": 1234, "track_unique_id": 10003, "deleted": 1, }, ] @pytest.fixture def fixture_assets_data_duplicate_records() -> list[Any]: """Fixture to return assets data.""" return [ { "id": 1, "filename": "original_filename_1_1", "product_id": 1234, "track_unique_id": 10001, }, { "id": 2, "filename": "original_filename_2_1", "product_id": 1234, "track_unique_id": 10002, }, { "id": 3, "filename": "original_filename_2_2", "product_id": 1234, "track_unique_id": 10002, }, { "id": 4, "filename": "original_filename_3_1", "product_id": 1234, "track_unique_id": 10003, }, { "id": 5, "filename": "original_filename_3_2", "product_id": 1234, "track_unique_id": 10003, }, ] @pytest.fixture def fixture_delete_response_success_data() -> dict[str, Any]: """Fixture to mock delete response response.""" return { "status": "failure", "details": { "bucket_1": { "succeeded": [ {"Key": "bucket_1_asset_1_file_1"}, {"Key": "bucket_1_asset_1_file_2"}, {"Key": "bucket_1_asset_2_file_1"}, ], "failed": [], }, "bucket_2": { "succeeded": [ {"Key": "bucket_2_asset_1_file_1"}, {"Key": "bucket_2_asset_1_file_2"}, {"Key": "bucket_2_asset_2_file_1"}, ], "failed": [], }, "bucket_3": { "failed": [], "succeeded": [{"Key": "bucket_3_asset_3_file_1"}], }, }, } @pytest.fixture def fixture_delete_response_failure_data() -> dict[str, Any]: """Fixture to mock delete response failure.""" return { "status": "failure", "details": { "bucket_1": { "succeeded": [ {"Key": "bucket_1_asset_1_file_1"}, {"Key": "bucket_1_asset_1_file_2"}, {"Key": "bucket_1_asset_2_file_1"}, ], "failed": [], }, "bucket_2": { "succeeded": [ {"Key": "bucket_2_asset_1_file_1"}, {"Key": "bucket_2_asset_1_file_2"}, ], "failed": [ { "Key": "bucket_2_asset_2_file_1", "Message": "Access Denied", "Code": "AccessDenied", } ], }, "bucket_3": { "failed": [{"Key": "bucket_3_asset_3_file_1"}], "succeeded": [], "error_code": "bucket_not_exists", }, }, } @pytest.fixture def fixture_bucket_filename_mapping() -> dict[Any, Any]: """Fixture to return bucket_filename mapping.""" return { ("bucket_1", "bucket_1_asset_1_file_1"): 1, ("bucket_1", "bucket_1_asset_1_file_2"): 1, ("bucket_1", "bucket_1_asset_2_file_1"): 2, ("bucket_2", "bucket_2_asset_1_file_1"): 1, ("bucket_2", "bucket_2_asset_1_file_2"): 1, ("bucket_2", "bucket_2_asset_2_file_1"): 2, ("bucket_3", "bucket_3_asset_3_file_1"): 3, } def test_group_files_by_assets_success( fixture_assets_data: list[Any], fixture_delete_response_success_data: dict[str, Any], fixture_bucket_filename_mapping: dict[Any, Any], snapshot: SnapshotAssertion, ) -> None: """Test for success of _group_files_by_assets.""" asset_ids = [item["id"] for item in fixture_assets_data] result = delete._group_files_by_assets( fixture_delete_response_success_data, asset_ids, fixture_bucket_filename_mapping ) assert result == snapshot def test_group_files_by_assets_failure( fixture_assets_data: list[Any], fixture_delete_response_failure_data: dict[str, Any], fixture_bucket_filename_mapping: dict[Any, Any], snapshot: SnapshotAssertion, ) -> None: """Test for failure of _group_files_by_assets.""" asset_ids = [item["id"] for item in fixture_assets_data] result = delete._group_files_by_assets( fixture_delete_response_failure_data, asset_ids, fixture_bucket_filename_mapping ) assert result == snapshot @pytest.fixture def fixture_assets_status_data() -> dict[Any, Any]: """Fixture to return asset_status data.""" return { 1: {"status": asset_status_constants.STATE_ENCODING_COMPLETED}, 2: {"status": asset_status_constants.STATE_ENCODING_COMPLETED}, 3: {"status": asset_status_constants.STATE_ENCODING_COMPLETED}, } @pytest.fixture def fixture_assets_final_data() -> dict[Any, Any]: """Fixture to return asset_final data.""" return { 1: [ { "bucket": "bucket_1", "filename": "bucket_1_asset_1_file_1", "asset_upload_id": 1, }, { "bucket": "bucket_1", "filename": "bucket_1_asset_1_file_2", "asset_upload_id": 1, }, { "bucket": "bucket_2", "filename": "bucket_2_asset_1_file_2", "asset_upload_id": 1, }, { "bucket": "bucket_2", "filename": "bucket_2_asset_1_file_1", "asset_upload_id": 1, }, ], 2: [ { "bucket": "bucket_1", "filename": "bucket_1_asset_2_file_1", "asset_upload_id": 2, }, { "bucket": "bucket_2", "filename": "bucket_2_asset_2_file_1", "asset_upload_id": 2, }, ], 3: [ { "bucket": "bucket_3", "filename": "bucket_3_asset_3_file_1", "asset_upload_id": 3, } ], } def test_check_assets_ready_to_delete_success( fixture_assets_data_duplicate_records: list[Any], ) -> None: """Test for _check_assets_ready_to_delete success.""" ( flexmock(asset_status) .should_receive("get_asset_statuses_by_asset_upload_ids") .with_args([1, 3, 5]) .and_return( { 1: {"status": asset_status_constants.STATUS_ENCODING_COMPLETED}, 3: {"status": asset_status_constants.STATUS_ACKNOWLEDGE_ERROR}, 5: {"status": asset_status_constants.STATUS_ENCODING_COMPLETED}, } ) ) delete._check_assets_ready_to_delete(fixture_assets_data_duplicate_records) def test_check_assets_ready_to_delete_failure( fixture_assets_data_duplicate_records: list[Any], ) -> None: """Test for _check_assets_ready_to_delete failure.""" asset_upload_ids = [1, 3, 5] ( flexmock(asset_status) .should_receive("get_asset_statuses_by_asset_upload_ids") .with_args(asset_upload_ids) .and_return( { 1: {"status": asset_status_constants.STATUS_ENCODING_COMPLETED}, 3: {"status": asset_status_constants.STATUS_ENCODING_PROGRESSING}, 5: {"status": asset_status_constants.STATUS_ENCODING_COMPLETED}, } ) ) with pytest.raises(WrongAssetStatus) as exc: delete._check_assets_ready_to_delete(fixture_assets_data_duplicate_records) assert ( exc.value.description == error_constants.ERROR_CODE_ASSET_NOT_READY_FOR_DELETE ) def test_check_assets_ready_to_delete_db_failure( fixture_assets_data_duplicate_records: list[Any], ) -> None: """Test for _check_assets_ready_to_delete db failure.""" asset_upload_ids = [1, 3, 5] error_message = "fatal_error" ( flexmock(asset_status) .should_receive("get_asset_statuses_by_asset_upload_ids") .with_args(asset_upload_ids) .and_raise(SQLAlchemyError(error_message)) ) with pytest.raises(SQLAlchemyError) as exc: delete._check_assets_ready_to_delete(fixture_assets_data_duplicate_records) assert str(exc.value) == error_message def test_check_assets_ready_to_delete_status_not_found( fixture_assets_data: list[Any], ) -> None: """Test for _check_assets_ready_to_delete status missing.""" asset_upload_ids = [1] ( flexmock(asset_status) .should_receive("get_asset_statuses_by_asset_upload_ids") .with_args(asset_upload_ids) .and_return({}) ) with pytest.raises(AssetStatusNotFound) as exc: delete._check_assets_ready_to_delete(fixture_assets_data[0:1]) assert exc.value.description == error_constants.ERROR_ASSET_STATUS_NOT_FOUND @pytest.fixture def delete_assets_mocks( fixture_assets_final_data: dict[Any, Any], fixture_assets_data: list[Any], fixture_assets_marked_deleted_data: list[Any], ) -> dict[str, Any]: """Mock subcalls for delete_assets.""" return { "ready_to_delete": None, "get_asset_finals": fixture_assets_final_data, "mark_deleted": fixture_assets_marked_deleted_data, } @pytest.fixture def fixture_delete_s3_files() -> list[Any]: """Return expected args for delete_s3_files call.""" return [ {"file": "bucket_1_asset_1_file_1", "bucket": "bucket_1"}, {"file": "bucket_1_asset_1_file_2", "bucket": "bucket_1"}, {"file": "bucket_2_asset_1_file_2", "bucket": "bucket_2"}, {"file": "bucket_2_asset_1_file_1", "bucket": "bucket_2"}, {"file": "bucket_1_asset_2_file_1", "bucket": "bucket_1"}, {"file": "bucket_2_asset_2_file_1", "bucket": "bucket_2"}, {"file": "bucket_3_asset_3_file_1", "bucket": "bucket_3"}, ] def test_delete_asset_uploads_success( fixture_assets_data: list[Any], delete_assets_mocks: dict[str, Any], fixture_delete_response_success_data: dict[str, Any], fixture_delete_s3_files: list[Any], snapshot: SnapshotAssertion, ) -> None: """Test for success of delete.""" asset_upload_ids = [asset["id"] for asset in fixture_assets_data] ( flexmock(delete) .should_receive("_check_assets_ready_to_delete") .with_args(fixture_assets_data) .and_return(delete_assets_mocks["ready_to_delete"]) ) ( flexmock(asset_final) .should_receive("get_asset_final_by_asset_upload_ids") .with_args(asset_upload_ids) .and_return(delete_assets_mocks["get_asset_finals"]) ) ( flexmock(asset_upload) .should_receive("mark_asset_upload_deleted") .and_return(delete_assets_mocks["mark_deleted"]) ) ( flexmock(s3_file) .should_receive("delete_s3_files") .with_args(fixture_delete_s3_files) .and_return(fixture_delete_response_success_data["details"]) ) (flexmock(asset_status).should_receive("create_asset_status").and_return(None)) result = delete.delete_assets(fixture_assets_data) assert result == snapshot def test_delete_asset_uploads_no_final_assets_success( fixture_assets_data: list[Any], delete_assets_mocks: dict[str, Any], snapshot: SnapshotAssertion, ) -> None: """Test for success of delete when no final assets exist.""" asset_upload_ids = [asset["id"] for asset in fixture_assets_data] ( flexmock(delete) .should_receive("_check_assets_ready_to_delete") .with_args(fixture_assets_data) .and_return(delete_assets_mocks["ready_to_delete"]) ) ( flexmock(asset_final) .should_receive("get_asset_final_by_asset_upload_ids") .with_args(asset_upload_ids) .and_raise(AssetFinalNotFound()) ) ( flexmock(asset_upload) .should_receive("mark_asset_upload_deleted") .and_return(delete_assets_mocks["mark_deleted"]) ) (flexmock(s3_file).should_receive("delete_s3_files").with_args([]).and_return({})) (flexmock(asset_status).should_receive("create_asset_status").and_return(None)) result = delete.delete_assets(fixture_assets_data) assert result == snapshot def test_delete_asset_uploads_failure( fixture_assets_data: list[Any], fixture_delete_response_failure_data: dict[str, Any], delete_assets_mocks: dict[str, Any], snapshot: SnapshotAssertion, ) -> None: """Test for failure of delete.""" asset_upload_ids = [asset["id"] for asset in fixture_assets_data] ( flexmock(delete) .should_receive("_check_assets_ready_to_delete") .with_args(fixture_assets_data) .and_return(delete_assets_mocks["ready_to_delete"]) ) ( flexmock(asset_final) .should_receive("get_asset_final_by_asset_upload_ids") .with_args(asset_upload_ids) .and_return(delete_assets_mocks["get_asset_finals"]) ) ( flexmock(asset_upload) .should_receive("mark_asset_upload_deleted") .and_return(delete_assets_mocks["mark_deleted"]) ) (flexmock(asset_status).should_receive("create_asset_status").and_return(None)) ( flexmock(s3_file) .should_receive("delete_s3_files") .and_return(fixture_delete_response_failure_data["details"]) ) with pytest.raises(AssetDeleteFailure) as exc: delete.delete_assets(fixture_assets_data) assert str(exc.value).replace("'", '"') == snapshot def test_delete_asset_uploads_ready_to_delete_failure( fixture_assets_data: list[Any], ) -> None: """Test for success of delete.""" ( flexmock(delete) .should_receive("_check_assets_ready_to_delete") .and_raise(SQLAlchemyError("fatal_error")) ) with pytest.raises(SQLAlchemyError) as exc: delete.delete_assets(fixture_assets_data) assert str(exc.value) == "fatal_error" def test_delete_asset_uploads_mark_asset_delete_failure( fixture_assets_data: list[Any], delete_assets_mocks: dict[str, Any] ) -> None: """Test for success of delete.""" (flexmock(delete).should_receive("_check_assets_ready_to_delete").and_return(None)) error_message = "fatal_error" ( flexmock(asset_upload) .should_receive("mark_asset_upload_deleted") .and_raise(SQLAlchemyError(error_message)) ) with pytest.raises(SQLAlchemyError) as exc: delete.delete_assets(fixture_assets_data) assert str(exc.value) == error_message def test_delete_asset_uploads_get_asset_finals_failure( fixture_assets_data: list[Any], delete_assets_mocks: dict[str, Any] ) -> None: """Test for success of delete.""" (flexmock(delete).should_receive("_check_assets_ready_to_delete").and_return(None)) ( flexmock(asset_upload) .should_receive("mark_asset_upload_deleted") .and_return(delete_assets_mocks["mark_deleted"]) ) error_message = "fatal_error" ( flexmock(asset_final) .should_receive("get_asset_final_by_asset_upload_ids") .and_raise(SQLAlchemyError(error_message)) ) with pytest.raises(SQLAlchemyError) as exc: delete.delete_assets(fixture_assets_data) assert str(exc.value) == error_message TRACK_ID = 10001 PRODUCT_ID = 100 @pytest.fixture def fixture_delete_track_mocks() -> dict[str, Any]: """Mock subcalls of delete_track.""" return { "get_track": {"product_id": PRODUCT_ID}, "get_product": {"status": "not_in_content"}, "get_asset": [{"asset_upload_id": 1}], "delete_asset": {"succeeded": [{"asset": {}, "delete_details": {}}]}, } def test_delete_track_success(fixture_delete_track_mocks: dict[str, Any]) -> None: """Test for delete track success without asset_upload_type filter.""" ( flexmock(ows_track) .should_receive("get_track_by_id") .with_args(TRACK_ID) .and_return(fixture_delete_track_mocks["get_track"]) ) ( flexmock(ows_product) .should_receive("get_product_by_id") .with_args(PRODUCT_ID) .and_return(fixture_delete_track_mocks["get_product"]) ) ( flexmock(asset_upload) .should_receive("get_asset_uploads") .with_args( track_id=TRACK_ID, api_version=api.API_VERSION_V2, asset_upload_type_id=None, ) .and_return(fixture_delete_track_mocks["get_asset"]) ) ( flexmock(delete) .should_receive("delete_assets") .with_args(fixture_delete_track_mocks["get_asset"]) .and_return(fixture_delete_track_mocks["delete_asset"]) ) result = delete.delete_track(TRACK_ID) assert result def test_delete_track_success_with_asset_upload_type( fixture_delete_track_mocks: dict[str, Any], ) -> None: """Test for delete track success with asset_upload_type filter.""" asset_upload_type_name = "stereo" asset_upload_type_id = 1 ( flexmock(ows_track) .should_receive("get_track_by_id") .with_args(TRACK_ID) .and_return(fixture_delete_track_mocks["get_track"]) ) ( flexmock(ows_product) .should_receive("get_product_by_id") .with_args(PRODUCT_ID) .and_return(fixture_delete_track_mocks["get_product"]) ) ( flexmock(asset_upload_type) .should_receive("resolve_asset_upload_type_id") .with_args(asset_upload_type_name) .and_return(asset_upload_type_id) ) ( flexmock(asset_upload) .should_receive("get_asset_uploads") .with_args( track_id=TRACK_ID, api_version=api.API_VERSION_V2, asset_upload_type_id=asset_upload_type_id, ) .and_return(fixture_delete_track_mocks["get_asset"]) ) ( flexmock(delete) .should_receive("delete_assets") .with_args(fixture_delete_track_mocks["get_asset"]) .and_return(fixture_delete_track_mocks["delete_asset"]) ) result = delete.delete_track(TRACK_ID, asset_upload_type_name) assert result def test_delete_track_get_track_failure() -> None: """Test for delete track get_track failure.""" ( flexmock(ows_track) .should_receive("get_track_by_id") .and_raise(HTTPError(response=MagicMock(status_code=500))) ) with pytest.raises(HTTPError) as exc: delete.delete_track(TRACK_ID) assert str(exc.value) == "" def test_delete_track_get_product_failure( fixture_delete_track_mocks: dict[str, Any], ) -> None: """Test for delete track get_product failure.""" ( flexmock(ows_track) .should_receive("get_track_by_id") .and_return(fixture_delete_track_mocks["get_track"]) ) ( flexmock(ows_product) .should_receive("get_product_by_id") .and_raise(HTTPError(response=MagicMock(status_code=500))) ) with pytest.raises(HTTPError) as exc: delete.delete_track(TRACK_ID) assert str(exc.value) == "" def test_delete_track_get_assets_failure( fixture_delete_track_mocks: dict[str, Any], ) -> None: """Test for delete track get_assets failure.""" error_message = "asset_not_found_or_already_deleted" ( flexmock(ows_track) .should_receive("get_track_by_id") .and_return(fixture_delete_track_mocks["get_track"]) ) ( flexmock(ows_product) .should_receive("get_product_by_id") .and_return(fixture_delete_track_mocks["get_product"]) ) ( flexmock(asset_upload) .should_receive("get_asset_uploads") .and_raise(SQLAlchemyError(error_message)) ) with pytest.raises(SQLAlchemyError) as exc: delete.delete_track(TRACK_ID) assert str(exc.value) == error_message def test_delete_track_delete_assets_failure( fixture_delete_track_mocks: dict[str, Any], ) -> None: """Test for delete track get_assets failure.""" error_message = "delete_asset_failure" ( flexmock(ows_track) .should_receive("get_track_by_id") .and_return(fixture_delete_track_mocks["get_track"]) ) ( flexmock(ows_product) .should_receive("get_product_by_id") .and_return(fixture_delete_track_mocks["get_product"]) ) ( flexmock(asset_upload) .should_receive("get_asset_uploads") .and_return(fixture_delete_track_mocks["get_asset"]) ) ( flexmock(delete) .should_receive("delete_assets") .and_raise(AssetDeleteFailure(error_message)) ) with pytest.raises(AssetDeleteFailure) as exc: delete.delete_track(TRACK_ID) assert str(exc.value) == error_message def test_delete_track_in_content_failure( fixture_delete_track_mocks: dict[str, Any], ) -> None: """Test for delete track in_content failure.""" ( flexmock(ows_track) .should_receive("get_track_by_id") .and_return(fixture_delete_track_mocks["get_track"]) ) ( flexmock(ows_product) .should_receive("get_product_by_id") .and_return({"status": product_constants.PRODUCT_STATUS_IN_CONTENT}) ) ( flexmock(asset_upload) .should_receive("get_asset_uploads") .and_return(fixture_delete_track_mocks["get_asset"]) ) ( flexmock(delete) .should_receive("delete_assets") .and_return(fixture_delete_track_mocks["delete_asset"]) ) with pytest.raises(InvalidProductStatus) as exc: delete.delete_track(TRACK_ID) assert exc.value.description == error_constants.ERROR_MESSAGE_PRODUCT_IN_CONTENT @pytest.fixture def fixture_delete_product_mocks() -> dict[str, Any]: """Mock subcalls of delete_product.""" return { "get_product": {"status": "not_in_content"}, "get_assets": [{"asset_upload_id": 1}], "delete_asset": {"succeeded": [{"asset": {}, "delete_details": {}}]}, } @pytest.fixture def fixture_delete_product_correction_mocks() -> dict[str, Any]: """Mock subcalls of delete_product_corrections.""" return { "get_asset_uploads_records": [ {"id": 1, "is_correction": 1, "track_unique_id": 0, "deleted": 0}, {"id": 2, "is_correction": 1, "track_unique_id": 123, "deleted": 0}, ], "mark_asset_upload_records_deleted": 2, } def test_delete_product_success(fixture_delete_product_mocks: dict[str, Any]) -> None: """Test for delete product success.""" ( flexmock(ows_product) .should_receive("get_product_by_id") .with_args(PRODUCT_ID) .and_return(fixture_delete_product_mocks["get_product"]) ) ( flexmock(asset_upload) .should_receive("get_asset_uploads") .with_args(product_id=PRODUCT_ID, api_version=api.API_VERSION_V2) .and_return(fixture_delete_product_mocks["get_assets"]) ) ( flexmock(delete) .should_receive("delete_assets") .with_args(fixture_delete_product_mocks["get_assets"]) .and_return(fixture_delete_product_mocks["delete_asset"]) ) result = delete.delete_product(PRODUCT_ID) assert result def test_delete_product_get_product_failure( fixture_delete_product_mocks: dict[str, Any], ) -> None: """Test for delete product get_product failure.""" ( flexmock(ows_product) .should_receive("get_product_by_id") .with_args(PRODUCT_ID) .and_raise(HTTPError(response=MagicMock(status_code=500))) ) with pytest.raises(HTTPError) as exc: delete.delete_product(PRODUCT_ID) assert str(exc.value) == "" def test_delete_product_delete_assets_failure( fixture_delete_product_mocks: dict[str, Any], ) -> None: """Test for delete product delete_assets failure.""" ( flexmock(ows_product) .should_receive("get_product_by_id") .with_args(PRODUCT_ID) .and_return(fixture_delete_product_mocks["get_product"]) ) ( flexmock(asset_upload) .should_receive("get_asset_uploads") .with_args(product_id=PRODUCT_ID, api_version=api.API_VERSION_V2) .and_return(fixture_delete_product_mocks["get_assets"]) ) error_message = "fatal_error" ( flexmock(delete) .should_receive("delete_assets") .with_args(fixture_delete_product_mocks["get_assets"]) .and_raise(AssetDeleteFailure(error_message)) ) with pytest.raises(AssetDeleteFailure) as exc: delete.delete_product(PRODUCT_ID) assert str(exc.value) == error_message def test_delete_product_get_assets_failure( fixture_delete_product_mocks: dict[str, Any], ) -> None: """Test for delete product get_assets failure.""" error_message = "fatal_error_delete_asset" ( flexmock(ows_product) .should_receive("get_product_by_id") .with_args(PRODUCT_ID) .and_return(fixture_delete_product_mocks["get_product"]) ) ( flexmock(asset_upload) .should_receive("get_asset_uploads") .with_args(product_id=PRODUCT_ID, api_version=api.API_VERSION_V2) .and_raise(SQLAlchemyError(error_message)) ) with pytest.raises(SQLAlchemyError) as exc: delete.delete_product(PRODUCT_ID) assert str(exc.value) == error_message def test_delete_product_in_content_failure( fixture_delete_product_mocks: dict[str, Any], ) -> None: """Test for delete product in_content failure.""" ( flexmock(ows_product) .should_receive("get_product_by_id") .with_args(PRODUCT_ID) .and_return({"status": product_constants.PRODUCT_STATUS_IN_CONTENT}) ) ( flexmock(asset_upload) .should_receive("get_asset_uploads") .with_args(product_id=PRODUCT_ID, api_version=api.API_VERSION_V2) .and_return(fixture_delete_product_mocks["get_assets"]) ) ( flexmock(delete) .should_receive("delete_assets") .with_args(fixture_delete_product_mocks["get_assets"]) .and_return(fixture_delete_product_mocks["delete_asset"]) ) with pytest.raises(InvalidProductStatus) as exc: delete.delete_product(PRODUCT_ID) assert exc.value.description == error_constants.ERROR_MESSAGE_PRODUCT_IN_CONTENT def test_delete_product_corrections_success( mocker: pytest_mock.MockerFixture, fixture_delete_product_correction_mocks: dict[str, Any], ) -> None: """Test for delete product corrections success.""" mock_au_db_session = mock_db_session(mocker, "au_db_session") ( flexmock(asset_upload) .should_receive("get_asset_uploads_records") .with_args( session=mock_au_db_session, api_version=api.API_VERSION_V2, product_id=PRODUCT_ID, is_correction=1, ) .and_return( fixture_delete_product_correction_mocks["get_asset_uploads_records"] ) ) ( flexmock(asset_upload) .should_receive("mark_asset_upload_records_deleted") .with_args(session=mock_au_db_session, asset_upload_ids=[1, 2]) .and_return( fixture_delete_product_correction_mocks["mark_asset_upload_records_deleted"] ) ) result = delete.delete_product_corrections(PRODUCT_ID) assert result == success_constants.DISCARDING_CORRECTION_SUCCESS.format(PRODUCT_ID) def test_delete_product_corrections_not_found( mocker: pytest_mock.MockerFixture, fixture_delete_product_correction_mocks: dict[str, Any], ) -> None: """Test for delete product corrections success.""" mock_au_db_session = mock_db_session(mocker, "au_db_session") ( flexmock(asset_upload) .should_receive("get_asset_uploads_records") .with_args( session=mock_au_db_session, api_version=api.API_VERSION_V2, product_id=PRODUCT_ID, is_correction=1, ) .and_raise( AssetUploadNotFound( error_constants.ERROR_NO_CORRECTIONS_TO_DISCARD.format(PRODUCT_ID) ) ) ) with pytest.raises(AssetUploadNotFound) as exc: delete.delete_product_corrections(PRODUCT_ID) assert ( exc.value.description == error_constants.ERROR_NO_CORRECTIONS_TO_DISCARD.format(PRODUCT_ID) ) def test_delete_product_corrections_update_error( mocker: pytest_mock.MockerFixture, fixture_delete_product_correction_mocks: dict[str, Any], ) -> None: """Test for delete product corrections success.""" mock_au_db_session = mock_db_session(mocker, "au_db_session") ( flexmock(asset_upload) .should_receive("get_asset_uploads_records") .with_args( session=mock_au_db_session, api_version=api.API_VERSION_V2, product_id=PRODUCT_ID, is_correction=1, ) .and_return( fixture_delete_product_correction_mocks["get_asset_uploads_records"] ) ) ( flexmock(asset_upload) .should_receive("mark_asset_upload_records_deleted") .with_args(session=mock_au_db_session, asset_upload_ids=[1, 2]) .and_return(1) ) with pytest.raises(ErrorDiscardingCorrections) as exc: delete.delete_product_corrections(PRODUCT_ID) assert ( str(exc.value) == "Error discarding corrections for product id 100. 1 records marked, 2 expected" )