from unittest.mock import AsyncMock from typing import List from server.client.clients.dsp_api import DspApiClient from tests.helpers import read_json_from_file def _get_youtube_performance_data() -> List: return [ { "dimensions": { "channel_id": "youtube_UComP_epzeKzvBX156r6pm1Q", "content_type": "partner_uploaded", "country_code": "worldwide", "date": "2022-06-01", "dsp": "youtube", "dsp_video_id": "niG3YMU6jFk", "isrc": None, "video_id": "youtube_niG3YMU6jFk" }, "metrics": { "average_view_duration_percentage": 68.39859, "average_view_duration_seconds": 159.36871, "comments": 11, "dislikes": 23, "likes": 810, "shares": 525, "traffic_source_types": { "browse_features": 6342, "direct_or_unknown": 1897, "external": 2536, "hashtag_pages": 7, "interactive_video_endscreen": 239, "notifications": 0, "other_youtube_features": 3428, "playlist_pages": 3473, "playlists": 77963, "product_pages": 0, "programming_from_claimed_content": 0, "shorts": 0, "sound_pages": 1, "stories": 0, "suggested_videos": 14610, "unknown": 0, "video_cards_and_annotations": 1, "youtube_advertising": 0, "youtube_channels": 3740, "youtube_search": 16361 }, "views": 130598 } }, { "dimensions": { "channel_id": "youtube_UComP_epzeKzvBX156r6pm1Q", "content_type": "partner_uploaded", "country_code": "worldwide", "date": "2022-06-02", "dsp": "youtube", "dsp_video_id": "niG3YMU6jFk", "isrc": None, "video_id": "youtube_niG3YMU6jFk" }, "metrics": { "average_view_duration_percentage": 66.23979, "average_view_duration_seconds": 154.33871, "comments": 8, "dislikes": 28, "likes": 764, "shares": 531, "traffic_source_types": { "browse_features": 5881, "direct_or_unknown": 1513, "external": 2431, "hashtag_pages": 7, "interactive_video_endscreen": 236, "notifications": 0, "other_youtube_features": 3396, "playlist_pages": 3945, "playlists": 79571, "product_pages": 0, "programming_from_claimed_content": 0, "shorts": 0, "sound_pages": 2, "stories": 0, "suggested_videos": 14109, "unknown": 0, "video_cards_and_annotations": 1, "youtube_advertising": 0, "youtube_channels": 3697, "youtube_search": 16579 }, "views": 131368 } }, { "dimensions": { "channel_id": "youtube_UComP_epzeKzvBX156r6pm1Q", "content_type": "partner_uploaded", "country_code": "worldwide", "date": "2022-06-03", "dsp": "youtube", "dsp_video_id": "niG3YMU6jFk", "isrc": None, "video_id": "youtube_niG3YMU6jFk" }, "metrics": { "average_view_duration_percentage": 65.50239, "average_view_duration_seconds": 152.62056, "comments": 8, "dislikes": 33, "likes": 854, "shares": 570, "traffic_source_types": { "browse_features": 5892, "direct_or_unknown": 1347, "external": 2387, "hashtag_pages": 16, "interactive_video_endscreen": 290, "notifications": 0, "other_youtube_features": 3958, "playlist_pages": 3629, "playlists": 82277, "product_pages": 0, "programming_from_claimed_content": 0, "shorts": 0, "sound_pages": 1, "stories": 0, "suggested_videos": 14585, "unknown": 0, "video_cards_and_annotations": 0, "youtube_advertising": 0, "youtube_channels": 3760, "youtube_search": 17467 }, "views": 135609 } }, { "dimensions": { "channel_id": "youtube_UComP_epzeKzvBX156r6pm1Q", "content_type": "partner_uploaded", "country_code": "worldwide", "date": "2022-06-04", "dsp": "youtube", "dsp_video_id": "niG3YMU6jFk", "isrc": None, "video_id": "youtube_niG3YMU6jFk" }, "metrics": { "average_view_duration_percentage": 63.76094, "average_view_duration_seconds": 148.56299, "comments": 16, "dislikes": 35, "likes": 857, "shares": 511, "traffic_source_types": { "browse_features": 5898, "direct_or_unknown": 1370, "external": 2378, "hashtag_pages": 16, "interactive_video_endscreen": 287, "notifications": 1, "other_youtube_features": 4408, "playlist_pages": 4033, "playlists": 80142, "product_pages": 0, "programming_from_claimed_content": 0, "shorts": 0, "sound_pages": 4, "stories": 0, "suggested_videos": 13655, "unknown": 0, "video_cards_and_annotations": 2, "youtube_advertising": 0, "youtube_channels": 3774, "youtube_search": 18484 }, "views": 134452 } }, { "dimensions": { "channel_id": "youtube_UComP_epzeKzvBX156r6pm1Q", "content_type": "partner_uploaded", "country_code": "worldwide", "date": "2022-06-05", "dsp": "youtube", "dsp_video_id": "niG3YMU6jFk", "isrc": None, "video_id": "youtube_niG3YMU6jFk" }, "metrics": { "average_view_duration_percentage": 65.6984, "average_view_duration_seconds": 153.07727, "comments": 5, "dislikes": 34, "likes": 794, "shares": 535, "traffic_source_types": { "browse_features": 5470, "direct_or_unknown": 1189, "external": 2241, "hashtag_pages": 11, "interactive_video_endscreen": 276, "notifications": 0, "other_youtube_features": 3439, "playlist_pages": 3502, "playlists": 70251, "product_pages": 0, "programming_from_claimed_content": 0, "shorts": 0, "sound_pages": 3, "stories": 0, "suggested_videos": 13290, "unknown": 0, "video_cards_and_annotations": 2, "youtube_advertising": 0, "youtube_channels": 3528, "youtube_search": 15826 }, "views": 119028 } } ] def generate_graph_response_item( timestampt, total = None, browse_features = None, direct_or_unknown = None, external = None, hashtag_pages = None, interactive_video_endscreen = None, notifications = None, other_youtube_features = None, playlist_pages = None, playlists = None, product_pages = None, programming_from_claimed_content = None, shorts = None, sound_pages = None, stories = None, suggested_videos = None, unknown = None, video_cards_and_annotations = None, youtube_advertising = None, youtube_channels = None, youtube_search = None ): if total: return { "y": { "total": total, "browse_features": browse_features, "direct_or_unknown": direct_or_unknown, "external": external, "hashtag_pages": hashtag_pages, "interactive_video_endscreen": interactive_video_endscreen, "notifications": notifications, "other_youtube_features": other_youtube_features, "playlist_pages": playlist_pages, "playlists": playlists, "product_pages": product_pages, "programming_from_claimed_content": programming_from_claimed_content, "shorts": shorts, "sound_pages": sound_pages, "stories": stories, "suggested_videos": suggested_videos, "unknown": unknown, "video_cards_and_annotations": video_cards_and_annotations, "youtube_advertising": youtube_advertising, "youtube_channels": youtube_channels, "youtube_search": youtube_search, }, "x": timestampt } return { "y": None, "x": timestampt } def generate_performance_daily_metric_item( timestampt, date, views = 0, shares = None, dislikes = None, average_view_duration_percentage = None, comments = None, average_view_duration_seconds = None, likes = None, playlist_pages = None, other_youtube_features = None, youtube_advertising = None, interactive_video_endscreen = None, product_pages = None, external = None, notifications = None, hashtag_pages = None, programming_from_claimed_content = None, shorts = None, sound_pages = None, suggested_videos = None, direct_or_unknown = None, stories = None, youtube_channels = None, unknown = None, youtube_search = None, playlists = None, browse_features = None, video_cards_and_annotations = None ): if views: return { "shares": shares, "timestampt": timestampt, "traffic_source_types": { "playlist_pages": playlist_pages, "other_youtube_features": other_youtube_features, "youtube_advertising": youtube_advertising, "interactive_video_endscreen": interactive_video_endscreen, "product_pages": product_pages, "external": external, "notifications": notifications, "hashtag_pages": hashtag_pages, "programming_from_claimed_content": programming_from_claimed_content, "shorts": shorts, "sound_pages": sound_pages, "suggested_videos": suggested_videos, "direct_or_unknown": direct_or_unknown, "stories": stories, "youtube_channels": youtube_channels, "unknown": unknown, "youtube_search": youtube_search, "playlists": playlists, "browse_features": browse_features, "video_cards_and_annotations": video_cards_and_annotations, }, "date": date, "dislikes": dislikes, "average_view_duration_percentage": average_view_duration_percentage, "comments": comments, "views": views, "average_view_duration_seconds": average_view_duration_seconds, "likes": likes, } return { "timestampt": timestampt, "traffic_source_types": None, "date": date, "views": 0, } async def test_track_performance(client, auth, mocker): params = { "video_id": "youtube_niG3YMU6jFk", "latest_date": "2022-06-17", } expected_json_response = { "trends": { "daily_trend": 0, "weekly_trend": -36, "weekly_views": 253480, "latest_date_views": 0, }, "daily_metrics": [ generate_performance_daily_metric_item(1655424000, "2022-06-17"), generate_performance_daily_metric_item(1655337600, "2022-06-16"), generate_performance_daily_metric_item(1655251200, "2022-06-15"), generate_performance_daily_metric_item(1655164800, "2022-06-14"), generate_performance_daily_metric_item(1655078400, "2022-06-13"), generate_performance_daily_metric_item(1654992000, "2022-06-12"), generate_performance_daily_metric_item(1654905600, "2022-06-11"), generate_performance_daily_metric_item(1654819200, "2022-06-10"), generate_performance_daily_metric_item(1654732800, "2022-06-09"), generate_performance_daily_metric_item(1654646400, "2022-06-08"), generate_performance_daily_metric_item(1654560000, "2022-06-07"), generate_performance_daily_metric_item(1654473600, "2022-06-06"), generate_performance_daily_metric_item( 1654387200, "2022-06-05", 119028, 535, 34, 65.6984, 5, 153.07727, 794, 3502, 3439, 0, 276, 0, 2241, 0, 11, 0, 0, 3, 13290, 1189, 0, 3528, 0, 15826, 70251, 5470, 2, ), generate_performance_daily_metric_item( 1654300800, "2022-06-04", 134452, 511, 35, 63.76094, 16, 148.56299, 857, 4033, 4408, 0, 287, 0, 2378, 1, 16, 0, 0, 4, 13655, 1370, 0, 3774, 0, 18484, 80142, 5898, 2, ) ], "biggest_traffic_source": {"percentage": 59, "sources": ["playlists"]}, } async def dsp_send(*args, **kwargs): return _get_youtube_performance_data() mocker.patch.object(DspApiClient, "_send_request", side_effect=dsp_send) response = await client.get(f"/api/youtube/track/performance/", headers=auth, params=params) response_json = await response.json() assert response_json == expected_json_response assert len(response_json["daily_metrics"]) == 14 async def test_track_graph(client, auth, mocker): params = { "video_id": "youtube_niG3YMU6jFk", "latest_date": "2022-06-14", } expected_json_response = { "coordinates": [ generate_graph_response_item( 1654041600, 130598, 6342, 1897, 2536, 7, 239, 0, 3428, 3473, 77963, 0, 0, 0, 1, 0, 14610, 0, 1, 0, 3740, 16361, ), generate_graph_response_item( 1654128000, 131368, 5881, 1513, 2431, 7, 236, 0, 3396, 3945, 79571, 0, 0, 0, 2, 0, 14109, 0, 1, 0, 3697, 16579, ), generate_graph_response_item( 1654214400, 135609, 5892, 1347, 2387, 16, 290, 0, 3958, 3629, 82277, 0, 0, 0, 1, 0, 14585, 0, 0, 0, 3760, 17467, ), generate_graph_response_item( 1654300800, 134452, 5898, 1370, 2378, 16, 287, 1, 4408, 4033, 80142, 0, 0, 0, 4, 0, 13655, 0, 2, 0, 3774, 18484, ), generate_graph_response_item( 1654387200, 119028, 5470, 1189, 2241, 11, 276, 0, 3439, 3502, 70251, 0, 0, 0, 3, 0, 13290, 0, 2, 0, 3528, 15826, ), generate_graph_response_item(1654473600, None), generate_graph_response_item(1654560000, None), generate_graph_response_item(1654646400, None), generate_graph_response_item(1654732800, None), generate_graph_response_item(1654819200, None), generate_graph_response_item(1654905600, None), generate_graph_response_item(1654992000, None), generate_graph_response_item(1655078400, None), generate_graph_response_item(1655164800, None), ] } async def dsp_send(*args, **kwargs): return _get_youtube_performance_data() mocker.patch.object(DspApiClient, "_send_request", side_effect=dsp_send) response = await client.get(f"/api/youtube/track/streams-graph/", headers=auth, params=params) response_json = await response.json() assert response_json == expected_json_response assert len(response_json["coordinates"]) == 14 async def test_track_videos(client, auth, mocker): params = { "isrc": "USSM12105973", "limit": 2, "offset": 2, "sort_by": ["-views", "video_title"], } expected_json_response = { "items": [ { "views": 16794411, "dsp_video_id": "6_mdXb6JDLI", "video_title": "Oh My God", "content_type": "partner_uploaded", "dsp": "youtube", "video_id": "youtube_6_mdXb6JDLI", "channel_title": "Adele - Topic", "thumbnails": { "default": { "height": 90, "url": "https://i.ytimg.com/vi/6_mdXb6JDLI/default.jpg", "width": 120 }, "high": { "height": 360, "url": "https://i.ytimg.com/vi/6_mdXb6JDLI/hqdefault.jpg", "width": 480 }, "medium": { "height": 180, "url": "https://i.ytimg.com/vi/6_mdXb6JDLI/mqdefault.jpg", "width": 320 } }, "duration_seconds": 226, "dsp_channel_id": "UCRw0x9_EfawqmgDI2IgQLLg", "date_uploaded": "2021-11-18", "channel_id": "youtube_UCRw0x9_EfawqmgDI2IgQLLg" }, { "views": 168066, "dsp_video_id": "-sN5IQkZCoA", "video_title": "Adele 愛黛兒 / Oh My God 我的天 (中字MV)", "content_type": "partner_uploaded", "dsp": "youtube", "video_id": "youtube_-sN5IQkZCoA", "channel_title": "台灣索尼音樂 Sony Music Taiwan", "thumbnails": { "default": { "height": 90, "url": "https://i.ytimg.com/vi/-sN5IQkZCoA/default.jpg", "width": 120 }, "high": { "height": 360, "url": "https://i.ytimg.com/vi/-sN5IQkZCoA/hqdefault.jpg", "width": 480 }, "medium": { "height": 180, "url": "https://i.ytimg.com/vi/-sN5IQkZCoA/mqdefault.jpg", "width": 320 } }, "duration_seconds": 232, "dsp_channel_id": "UCFtUq0ml-coWmD70Pt_urRA", "date_uploaded": "2022-01-20", "channel_id": "youtube_UCFtUq0ml-coWmD70Pt_urRA" } ] } dsp_response = read_json_from_file("clients/dsp_api/youtube_videos") async_mock = AsyncMock(return_value=dsp_response) mocker.patch.object(DspApiClient, "_send_request", side_effect=async_mock) response = await client.get(f"/api/youtube/track/videos/", headers=auth, params=params) response_json = await response.json() assert response_json == expected_json_response