"""Tests for check_ownership logic.""" from typing import Any from unittest.mock import MagicMock import pytest from flexmock import flexmock from requests import HTTPError from assets.constants import error from assets.exceptions import ( AssetUploadNotFound, ProductNotFound, TrackNotFound, VendorNotFound, ) from assets.logic import asset_upload as asset_upload_logic, ownership from assets.models import ows_account, ows_product, ows_track from assets.models.cache import ownership as ownership_model ALW_HEADERS = { "Orchard-User-Id": "alw:12345", "Grass-Account-Id": "234234", "Grass-Account-Type": "vendor", } @pytest.fixture def correct_ownership_data() -> dict[str, Any]: """Fixture with correct check_ownership params.""" return {"account_type": "vendor", "account_id": 123, "product_id": 321} @pytest.fixture def correct_track_ownership_data() -> dict[str, Any]: """Fixture with correct check_track_ownership ownership params.""" return {"track_id": 111, "account_type": "vendor", "account_id": 123} def test_check_ownership_success(correct_ownership_data: dict[str, Any]) -> None: """Test for successful check_ownership call.""" expected_status = 200 (flexmock(ows_product).should_receive("check_ownership").and_return(None)) ( flexmock(ownership_model) .should_receive("get") .with_args( ownership_model.ENTITY_TYPE_PRODUCT, correct_ownership_data["product_id"], correct_ownership_data["account_type"], correct_ownership_data["account_id"], ) .and_return(None) ) ( flexmock(ownership_model) .should_receive("save") .with_args( ownership_model.ENTITY_TYPE_PRODUCT, correct_ownership_data["product_id"], correct_ownership_data["account_type"], correct_ownership_data["account_id"], True, ) .and_return(None) ) result = ownership.check_ownership(**correct_ownership_data) assert result assert result.status == expected_status @pytest.mark.parametrize( "ownership_value,expected_status", [ (True, 200), (False, 403), ], ) def test_check_ownership_cached_success( ownership_value: bool, expected_status: int, correct_ownership_data: dict[str, Any] ) -> None: """Test for successful ownership check with cached data.""" cached_ownership = {"ownership": ownership_value, "created": "created_time"} ( flexmock(ownership_model) .should_receive("get") .with_args( ownership_model.ENTITY_TYPE_PRODUCT, correct_ownership_data["product_id"], correct_ownership_data["account_type"], correct_ownership_data["account_id"], ) .and_return(cached_ownership) ) (flexmock(ows_product).should_receive("check_ownership").never()) result = ownership.check_ownership(**correct_ownership_data) assert result.status == expected_status def test_check_ownership_fail(correct_ownership_data: dict[str, Any]) -> None: """Test for check_ownership fail.""" ( flexmock(ows_product) .should_receive("check_ownership") .and_raise(HTTPError(response=MagicMock(status_code=403))) ) ( flexmock(ownership_model) .should_receive("get") .with_args( ownership_model.ENTITY_TYPE_PRODUCT, correct_ownership_data["product_id"], correct_ownership_data["account_type"], correct_ownership_data["account_id"], ) .and_return(None) ) ( flexmock(ownership_model) .should_receive("save") .with_args( ownership_model.ENTITY_TYPE_PRODUCT, correct_ownership_data["product_id"], correct_ownership_data["account_type"], correct_ownership_data["account_id"], False, ) .and_return(None) ) result = ownership.check_ownership(**correct_ownership_data) assert not result assert result.status == 403 def test_check_track_ownership_success( correct_track_ownership_data: dict[str, Any], ) -> None: """Test for check track ownership.""" expected_product_id = 10 ( flexmock(ownership_model) .should_receive("get") .with_args( ownership_model.ENTITY_TYPE_TRACK, correct_track_ownership_data["track_id"], correct_track_ownership_data["account_type"], correct_track_ownership_data["account_id"], ) .and_return(None) ) ( flexmock(ows_track) .should_receive("get_track_by_id") .with_args(correct_track_ownership_data["track_id"]) .and_return({"product_id": expected_product_id}) .once() ) ( flexmock(ows_product) .should_receive("check_ownership") .with_args( expected_product_id, correct_track_ownership_data["account_type"], correct_track_ownership_data["account_id"], ) .and_return(None) .once() ) ( flexmock(ownership_model) .should_receive("save") .with_args( ownership_model.ENTITY_TYPE_TRACK, correct_track_ownership_data["track_id"], correct_track_ownership_data["account_type"], correct_track_ownership_data["account_id"], True, ) .and_return(None) ) result = ownership.check_track_ownership(**correct_track_ownership_data) assert result assert result.status == 200 @pytest.mark.parametrize( "ownership_value,expected_status", [ (True, 200), (False, 403), ], ) def test_check_track_ownership_cached_success( ownership_value: bool, expected_status: int, correct_track_ownership_data: dict[str, Any], ) -> None: """Test for check track ownership from cache.""" cached_ownership = {"ownership": ownership_value, "created": "created_time"} ( flexmock(ownership_model) .should_receive("get") .with_args( ownership_model.ENTITY_TYPE_TRACK, correct_track_ownership_data["track_id"], correct_track_ownership_data["account_type"], correct_track_ownership_data["account_id"], ) .and_return(cached_ownership) ) (flexmock(ows_track).should_receive("get_track_by_id").never()) (flexmock(ows_product).should_receive("check_ownership").never()) result = ownership.check_track_ownership(**correct_track_ownership_data) assert result.status == expected_status def test_check_track_ownership_fail( correct_track_ownership_data: dict[str, Any], ) -> None: """Test for check track ownership fail.""" expected_product_id = 10 ( flexmock(ownership_model) .should_receive("get") .with_args( ownership_model.ENTITY_TYPE_TRACK, correct_track_ownership_data["track_id"], correct_track_ownership_data["account_type"], correct_track_ownership_data["account_id"], ) .and_return(None) ) ( flexmock(ows_track) .should_receive("get_track_by_id") .with_args(correct_track_ownership_data["track_id"]) .and_return({"product_id": expected_product_id}) .once() ) ( flexmock(ows_product) .should_receive("check_ownership") .with_args( expected_product_id, correct_track_ownership_data["account_type"], correct_track_ownership_data["account_id"], ) .and_raise(HTTPError(response=MagicMock(status_code=403))) .once() ) ( flexmock(ownership_model) .should_receive("save") .with_args( ownership_model.ENTITY_TYPE_TRACK, correct_track_ownership_data["track_id"], correct_track_ownership_data["account_type"], correct_track_ownership_data["account_id"], False, ) .and_return(None) ) result = ownership.check_track_ownership(**correct_track_ownership_data) assert not result assert result.status == 403 def test_check_track_ownership_error( correct_track_ownership_data: dict[str, Any], ) -> None: """Test for check track ownership with error in ows_track.""" ( flexmock(ownership_model) .should_receive("get") .with_args( ownership_model.ENTITY_TYPE_TRACK, correct_track_ownership_data["track_id"], correct_track_ownership_data["account_type"], correct_track_ownership_data["account_id"], ) .and_return(None) ) ( flexmock(ows_track) .should_receive("get_track_by_id") .with_args(correct_track_ownership_data["track_id"]) .and_raise(TrackNotFound(error.ERROR_TRACK_NOT_FOUND)) .once() ) (flexmock(ows_product).should_receive("check_ownership").never()) with pytest.raises(TrackNotFound) as exc: ownership.check_track_ownership(**correct_track_ownership_data) assert exc.value.description == error.ERROR_TRACK_NOT_FOUND def test_check_vendor_ownership_success( fixture_vendor_id: int, fixture_vendor_entity: str ) -> None: """Test for check_vendor_ownership call success.""" ( flexmock(ows_account) .should_receive("lookup_vendor") .with_args(fixture_vendor_id) .and_return(None) ) ownership.check_vendor_ownership( fixture_vendor_id, fixture_vendor_entity, str(fixture_vendor_id) ) def test_check_vendor_ownership_vendor_not_found( fixture_vendor_id: int, fixture_vendor_entity: str ) -> None: """Test check_vendor_ownership function when vendor_id does not exist.""" account_id = "123" ( flexmock(ows_account) .should_receive("lookup_vendor") .with_args(fixture_vendor_id) .and_raise(VendorNotFound(error.ERROR_VENDOR_NOT_FOUND)) ) with pytest.raises(VendorNotFound) as exc: ownership.check_vendor_ownership( fixture_vendor_id, fixture_vendor_entity, account_id ) assert exc.value.description == error.ERROR_VENDOR_NOT_FOUND def test_check_vendor_ownership_error( fixture_vendor_id: int, fixture_vendor_entity: str ) -> None: """Test check_vendor_ownership when vendor_id does not belong to Account ID.""" expected_status = 403 account_id = "123" mock_response = MagicMock(status_code=200, message=error.ERROR_VENDOR_NOT_OWNED) ( flexmock(ows_account) .should_receive("lookup_vendor") .with_args(fixture_vendor_id) .and_return(mock_response) ) result = ownership.check_vendor_ownership( fixture_vendor_id, fixture_vendor_entity, account_id ) assert not result assert result.status == expected_status assert result.errors["message"] == error.ERROR_VENDOR_NOT_OWNED def test_check_vendor_ownership_failure( fixture_vendor_id: int, fixture_vendor_entity: str ) -> None: """Test check_vendor_ownership received 500 error from ows-account.""" account_id = "123" ( flexmock(ows_account) .should_receive("lookup_vendor") .with_args(fixture_vendor_id) .and_raise(HTTPError(response=MagicMock(status_code=500))) ) with pytest.raises(HTTPError) as exc: ownership.check_vendor_ownership( fixture_vendor_id, fixture_vendor_entity, account_id ) assert str(exc.value) == "" def test_get_asset_owner_success() -> None: """Test get_asset_owner returns vendor and subaccount ids for a product.""" filename = "some_asset.wav" product_id = 999 subaccount_id = 111 vendor_id = "42" expected_owner = {"vendor_id": int(vendor_id), "subaccount_id": subaccount_id} ( flexmock(asset_upload_logic) .should_receive("get_asset_upload_by_filename") .with_args(filename) .and_return({"product_id": product_id}) .once() ) ( flexmock(ows_product) .should_receive("get_product_by_id") .with_args(product_id) .and_return({"vendor_id": vendor_id, "subaccount_id": subaccount_id}) .once() ) result = ownership.get_asset_product_owner(filename) assert result == expected_owner def test_get_asset_owner_zero_returned() -> None: """Test get_asset_owner returns zero owner ids when ows-product returns zero values.""" filename = "some_asset.wav" product_id = 999 ( flexmock(asset_upload_logic) .should_receive("get_asset_upload_by_filename") .with_args(filename) .and_return({"product_id": product_id}) .once() ) ( flexmock(ows_product) .should_receive("get_product_by_id") .with_args(product_id) .and_return({"vendor_id": None, "subaccount_id": None}) .once() ) result = ownership.get_asset_product_owner(filename) assert result == {"vendor_id": 0, "subaccount_id": 0} def test_get_asset_owner_asset_not_found() -> None: """Test get_asset_owner raises AssetUploadNotFound when asset does not exist.""" filename = "missing_asset.wav" ( flexmock(asset_upload_logic) .should_receive("get_asset_upload_by_filename") .with_args(filename) .and_raise(AssetUploadNotFound(error.ERROR_ASSET_UPLOAD_NOT_FOUND)) .once() ) (flexmock(ows_product).should_receive("get_product_by_id").never()) with pytest.raises(AssetUploadNotFound): ownership.get_asset_product_owner(filename) @pytest.mark.parametrize( "product_id", [pytest.param(0, id="zero"), pytest.param(None, id="none")], ) def test_get_asset_owner_no_product_id(product_id: int | None) -> None: """Test get_asset_owner raises ProductNotFound when product_id is absent.""" filename = "asset_no_product.wav" ( flexmock(asset_upload_logic) .should_receive("get_asset_upload_by_filename") .with_args(filename) .and_return({"product_id": product_id}) .once() ) (flexmock(ows_product).should_receive("get_product_by_id").never()) with pytest.raises(ProductNotFound): ownership.get_asset_product_owner(filename) def test_get_asset_owner_product_not_found_in_ows_product() -> None: """Test get_asset_owner raises ProductNotFound when ows-product returns 404.""" filename = "some_asset.wav" product_id = 999 ( flexmock(asset_upload_logic) .should_receive("get_asset_upload_by_filename") .with_args(filename) .and_return({"product_id": product_id}) .once() ) ( flexmock(ows_product) .should_receive("get_product_by_id") .with_args(product_id) .and_raise(ProductNotFound(error.ERROR_RELEASE_NOT_FOUND)) .once() ) with pytest.raises(ProductNotFound): ownership.get_asset_product_owner(filename)