import pytest from unittest.mock import Mock from unittest.mock import patch from unittest.mock import create_autospec from labelaudit.logic import asset_search from labelaudit.connectors.youtube_api import ServiceMapping upc = '889845009122' @pytest.fixture def single_asset_response(): return { 'kind': 'youtubePartner#assetSnippetList', 'items': [{ 'kind': 'youtubePartner#assetSnippet', 'id': 'A820245425510328', 'type': 'sound_recording', 'title': 'Cigarette', 'isrc': 'GBJVC1500004' }], 'pageInfo': { 'totalResults': 1 } } def multi_asset_search_response(num_in_page, num_total, next_token=None): """Generates a fake AssetSearch.list response. Args: num_in_page (int): Number of assets to be in this response page num_total (int): Number of total assets for the fake result set next_token (str): Optional token for next page of fake results Return: dict: Dictionary with the structure of an AssetSearch.list response. """ items = [] for i in range(1, num_in_page + 1): item = { 'kind': 'youtubePartner#assetSnippet', 'id': 'asset-id-{}'.format(i), 'type': 'sound_recording', 'title': 'Awesome Song #{}'.format(i), 'isrc': '%012d' % i } items.append(item) response = { 'kind': 'youtubePartner#assetSnippetList', 'items': items, 'pageInfo': { 'totalResults': num_total } } if next_token: response['nextPageToken'] = next_token return response @pytest.fixture def single_asset_list_response(): return { 'items': [{ 'metadataMine': { 'customId': '889176217043_MXF551051976_18520096', 'album': 'Coleccion de Reflexiones', 'genre': ['Other'], 'label': 'MultiMusic Mexico', 'isrc': 'MXF551051976', 'upc': '889176217043', 'title': 'Mi Cristo Roto', 'artist': ['Augusto A. Pérez Gutiérrez'] } }] } @pytest.fixture def multi_asset_list_response(): return { 'items': [{ 'metadataMine': { 'customId': '889176217043_MXF551051976_18520096', 'album': 'Coleccion de Reflexiones', 'genre': ['Other'], 'label': 'MultiMusic Mexico', 'isrc': 'MXF551051976', 'upc': '889176464430', 'title': 'Mi Cristo Roto', 'artist': ['Augusto A. Pérez Gutiérrez'] } }, { 'metadataMine': { 'customId': '889176464430_CAM461035496_18943955', 'album': 'Classic R & B Love Songs – 30 Sexy R n B Anthems', 'genre': ['Pop'], 'label': 'Urban Unlimited', 'isrc': 'CAM461035496', 'upc': '889845009122', 'title': 'Dont Phunk with My Heart', 'artist': ['Urban Unlimited'] } }] } def test_search_by_upc_params(): with patch.object(ServiceMapping, 'youtube_partner') as partner: asset_search.search_by_upc(upc, asset_search.OWNER_ORCHARD, True) partner.assetSearch().list.assert_called_with( ownershipRestriction=asset_search.OWNER_RESTRICTION_MINE, onBehalfOfContentOwner='theorchardmusic', metadataSearchFields='upc:{}'.format(upc), type='sound_recording', pageToken=None) def test_search_by_upc_token(): with patch.object(ServiceMapping, 'youtube_partner') as partner: token = 'not-a-real-token' asset_search.search_by_upc( upc, asset_search.OWNER_ORCHARD, True, token) partner.assetSearch().list.assert_called_with( ownershipRestriction=asset_search.OWNER_RESTRICTION_MINE, onBehalfOfContentOwner='theorchardmusic', metadataSearchFields='upc:{}'.format(upc), type='sound_recording', pageToken=token) def test_search_by_upc_no_restriction(): with patch.object(ServiceMapping, 'youtube_partner') as partner: asset_search.search_by_upc(upc, asset_search.OWNER_ORCHARD, False) partner.assetSearch().list.assert_called_with( ownershipRestriction=asset_search.OWNER_RESTRICTION_NONE, onBehalfOfContentOwner=asset_search.OWNER_ORCHARD, metadataSearchFields='upc:{}'.format(upc), type='sound_recording', pageToken=None) def test_search_by_upc_ioda(): with patch.object(ServiceMapping, 'youtube_partner') as partner: asset_search.search_by_upc(upc, asset_search.OWNER_IODA, True) partner.assetSearch().list.assert_called_with( ownershipRestriction=asset_search.OWNER_RESTRICTION_MINE, onBehalfOfContentOwner=asset_search.OWNER_IODA, metadataSearchFields='upc:{}'.format(upc), type='sound_recording', pageToken=None) def test_search_by_upc_result(monkeypatch, single_asset_response): def assetSearch(): def list(ownershipRestriction, onBehalfOfContentOwner, metadataSearchFields, type, pageToken): def execute(): return single_asset_response return Mock(execute=execute) return Mock(list=list) with patch.object(ServiceMapping, 'youtube_partner') as partner: monkeypatch.setattr(partner, 'assetSearch', assetSearch) response = asset_search.search_by_upc( upc, asset_search.OWNER_ORCHARD, True) assert response == single_asset_response def test_group_my_asset_ids(monkeypatch): owner = asset_search.OWNER_ORCHARD response = multi_asset_search_response(52, 52) mock_search_by_upc = create_autospec( asset_search.search_by_upc, return_value=response) monkeypatch.setattr(asset_search, 'search_by_upc', mock_search_by_upc) asset_ids = [] for item in response.get('items'): asset_ids.append(item.get('id')) slice1 = asset_ids[0:50] slice2 = asset_ids[50:52] group_gen = asset_search.group_my_asset_ids(upc, owner) assert next(group_gen) == slice1 assert next(group_gen) == slice2 @patch.object(ServiceMapping, 'youtube_partner') def test_list_assets_params(mock_partner): assets_ids = ['asset-1', 'asset-2'] asset_search.list_assets(assets_ids, asset_search.OWNER_ORCHARD) mock_partner.assets().list.assert_called_with( id='asset-1,asset-2', fetchMetadata='mine', fields='items/metadataMine', onBehalfOfContentOwner=asset_search.OWNER_ORCHARD) @patch.object(ServiceMapping, 'youtube_partner') def test_list_assets_response( mock_partner, monkeypatch, single_asset_response): def assets(): def list(id, fetchMetadata, fields, onBehalfOfContentOwner): def execute(): return single_asset_list_response return Mock(execute=execute) return Mock(list=list) asset_ids = ['A713064792817504'] monkeypatch.setattr(mock_partner, 'assets', assets) response = asset_search.list_assets( asset_ids, asset_search.OWNER_ORCHARD) assert response == single_asset_list_response def test_fetch_my_assets(monkeypatch, multi_asset_list_response): asset_ids = ['asset-1', 'asset-2'] def asset_id_gen(upc, content_owner): yield asset_ids monkeypatch.setattr(asset_search, 'group_my_asset_ids', asset_id_gen) fake_list_assets = Mock(return_value=multi_asset_list_response) monkeypatch.setattr(asset_search, 'list_assets', fake_list_assets) fetch = asset_search.fetch_my_assets(upc, asset_search.OWNER_ORCHARD) fetched_asset = next(fetch) assert fetched_asset == multi_asset_list_response.get('items')[1] with pytest.raises(StopIteration): next(fetch) def test_count_my_assets(monkeypatch, multi_asset_list_response): def fake_my_assets(upc, content_owner): yield multi_asset_list_response.get('items')[1] monkeypatch.setattr(asset_search, 'fetch_my_assets', fake_my_assets) num_assets = asset_search.count_my_assets(upc, asset_search.OWNER_ORCHARD) assert num_assets == 1