def test_video_endpoint(client): """Test video endpoint""" video1 = VideoFactory.create( last_modified=datetime(2019, 10, 4, tzinfo=pytz.utc)) video2 = VideoFactory.create( last_modified=datetime(2019, 10, 6, tzinfo=pytz.utc)) video3 = VideoFactory.create( last_modified=datetime(2019, 10, 5, tzinfo=pytz.utc)) resp = client.get(reverse("videos-list")) assert resp.data.get("count") == 3 assert list(map(lambda video: video["id"], resp.data.get("results"))) == [ video1.id, video2.id, video3.id, ] resp = client.get(reverse("videos-list") + "new/") assert resp.data.get("count") == 3 assert list(map(lambda video: video["id"], resp.data.get("results"))) == [ video2.id, video3.id, video1.id, ] resp = client.get(reverse("videos-detail", args=[video1.id])) assert resp.data.get("video_id") == video1.video_id
def test_extract_videos_topics(mocker, use_video_ids): """Tests that extract_videos_topics yields objects for each video with topics""" published_videos = VideoFactory.create_batch(3, published=True) # shouldn't be extracted VideoFactory.create_batch(3, published=False) topic_results = [[f"topic-{idx}-a", f"topic-{idx}-b"] for idx in range(len(published_videos))] mock_get_similar_topics = mocker.patch( "course_catalog.etl.video.get_similar_topics", side_effect=topic_results) if use_video_ids: published_videos = published_videos[:1] result = list( extract_videos_topics( video_ids=[published_videos[0].id] if use_video_ids else None)) assert len(result) == len(published_videos) for video, topics in zip(published_videos, topic_results): assert { "video_id": video.video_id, "platform": video.platform, "topics": [{ "name": topic } for topic in topics], } in result assert mock_get_similar_topics.call_count == (1 if use_video_ids else len(published_videos))
def test_delete_video(mocker): """Tests that deleting a video triggers a delete on a video document""" patched_delete_task = mocker.patch("search.task_helpers.delete_document") video = VideoFactory.create() delete_video(video) assert patched_delete_task.delay.called is True assert patched_delete_task.delay.call_args[0] == (gen_video_id(video), VIDEO_TYPE)
def test_load_playlist(mock_tasks): """Test load_playlist""" channel = VideoChannelFactory.create(playlists=None) playlist = PlaylistFactory.build() assert Playlist.objects.count() == 0 assert Video.objects.count() == 0 videos_records = VideoFactory.build_batch(5, published=True) videos_data = [model_to_dict(video) for video in videos_records] for video_data in videos_data: video_data["runs"] = [{ "run_id": video_data["video_id"], "platform": video_data["platform"], "prices": [{ "price": 0 }], }] props = model_to_dict(playlist) del props["id"] del props["channel"] props["videos"] = videos_data result = load_playlist(channel, props) assert isinstance(result, Playlist) assert result.videos.count() == len(videos_records) assert result.channel == channel mock_tasks.get_video_topics.delay.assert_called_once_with(video_ids=list( result.videos.order_by("id").values_list("id", flat=True)))
def test_upsert_video(mocker): """ Tests that upsert_video calls update_field_values_by_query with the right parameters """ patched_task = mocker.patch("search.tasks.upsert_video") video = VideoFactory.create() upsert_video(video.id) patched_task.delay.assert_called_once_with(video.id)
def test_serialize_video_for_bulk(): """ Test that serialize_video_for_bulk yields a valid ESVideoSerializer """ video = VideoFactory.create() assert serialize_video_for_bulk(video) == { "_id": gen_video_id(video), **ESVideoSerializer(video).data, }
def test_serialize_bulk_video(mocker): """ Test that serialize_bulk_video calls serialize_video_for_bulk for every existing video """ mock_serialize_video = mocker.patch("search.serializers.serialize_video_for_bulk") videos = VideoFactory.create_batch(5) list(serialize_bulk_videos(Video.objects.values_list("id", flat=True))) for video in videos: mock_serialize_video.assert_any_call(video)
def test_load_video(mock_upsert_tasks, video_exists, is_published): """Test that load_video loads the video""" video = (VideoFactory.create( published=is_published) if video_exists else VideoFactory.build()) assert Video.objects.count() == (1 if video_exists else 0) props = model_to_dict( VideoFactory.build(video_id=video.video_id, platform=video.platform, published=is_published)) del props["id"] props["runs"] = [{ "run_id": video.video_id, "platform": video.platform, "prices": [{ "price": 0 }] }] result = load_video(props) if video_exists and not is_published: mock_upsert_tasks.delete_video.assert_called_with(result) elif is_published: mock_upsert_tasks.upsert_video.assert_called_with(result.id) else: mock_upsert_tasks.delete_video.assert_not_called() mock_upsert_tasks.upsert_video.assert_not_called() assert Video.objects.count() == 1 # assert we got a course back assert isinstance(result, Video) # verify a free price assert result.runs.count() == 1 assert result.runs.first().prices.count() == 1 assert result.runs.first().prices.first().price == 0 for key, value in props.items(): assert getattr(result, key) == value, f"Property {key} should equal {value}"
def test_load_video_channels_unpublish(mock_upsert_tasks): """Test load_video_channels when a video/playlist gets unpublished""" channel = VideoChannelFactory.create() playlist = PlaylistFactory.create(channel=channel, published=True) video = VideoFactory.create() PlaylistVideo.objects.create(playlist=playlist, video=video, position=0) unpublished_playlist = PlaylistFactory.create(channel=channel, published=False) unpublished_video = VideoFactory.create() PlaylistVideo.objects.create(playlist=unpublished_playlist, video=unpublished_video, position=0) # inputs don't matter here load_video_channels([]) video.refresh_from_db() unpublished_video.refresh_from_db() assert video.published is True assert unpublished_video.published is False mock_upsert_tasks.delete_video.assert_called_once_with(unpublished_video)
def test_extract_topics(settings, mocker): """Tests that extract_topics looks up similar topics given a video""" video = VideoFactory.create() topics = ["topic a", "topic b"] mock_get_similar_topics = mocker.patch( "course_catalog.etl.video.get_similar_topics", return_value=topics) assert extract_topics(video) == [{"name": topic} for topic in topics] mock_get_similar_topics.assert_called_once_with( { "title": video.title, "short_description": video.short_description }, settings.OPEN_VIDEO_MAX_TOPICS, settings.OPEN_VIDEO_MIN_TERM_FREQ, settings.OPEN_VIDEO_MIN_DOC_FREQ, )
def test_popular_content_serializer(mocker, is_deleted, user): """Test PopularContentSerializer""" resources = [ VideoFactory.create(), ProgramFactory.create(), CourseFactory.create(), UserListFactory.create(), BootcampFactory.create(), ] data = [{ "content_type_id": ContentType.objects.get_for_model(resource).id, "content_id": resource.id, } for resource in resources] if is_deleted: for resource in resources: resource.delete() resources = [] resources = [ type(resource).objects.filter( id=resource.id).prefetch_list_items_for_user( user).annotate_is_favorite_for_user(user).first() for resource in resources ] context = {"request": mocker.Mock(user=user)} # NOTE: we test PopularContentSerializer instead of PopularContentListSerializer # because the list serializer is never used directly, but rather many=True tells # PopularContentSerializer to delegate to PopularContentListSerializer results = PopularContentSerializer(data, context=context, many=True).data # should be sorted by the same order they were passed in assert_json_equal( results, [ GenericForeignKeyFieldSerializer(resource, context=context).data for resource in resources ], )
def test_popular_content_types(client, user, mocker): """Test the popular content types API""" # create 2 of each, generate interactions for only the first one # second one shouldn't show up in the results course = CourseFactory.create_batch(2)[0] bootcamp = BootcampFactory.create_batch(2)[0] program = ProgramFactory.create_batch(2)[0] user_list = UserListFactory.create_batch(2)[0] video = VideoFactory.create_batch(2)[0] # generate interactions with an increasing count interactions = [ ContentTypeInteractionFactory.create_batch(count + 1, content=content)[0] for count, content in enumerate( [user_list, bootcamp, video, course, program]) ] response = client.get(reverse("popular_content-list")) # the response should be ordered such that items with a higher count of interactions are first # this ends up being the reverse order of `interactions` since we used `enumerate()` assert response.json() == { "results": PopularContentSerializer( [{ "content_type_id": interaction.content_type_id, "content_id": interaction.content_id, } for interaction in reversed(interactions)], many=True, context={ "request": mocker.Mock(user=user) }, ).data, "next": None, "previous": None, "count": len(interactions), }
def test_load_videos(): """Verify that load_videos loads a list of videos""" assert Video.objects.count() == 0 videos_records = VideoFactory.build_batch(5, published=True) videos_data = [model_to_dict(video) for video in videos_records] for video_data in videos_data: video_data["runs"] = [{ "run_id": video_data["video_id"], "platform": video_data["platform"], "prices": [{ "price": 0 }], }] results = load_videos(videos_data) assert len(results) == len(videos_records) assert Video.objects.count() == len(videos_records)
def test_get_youtube_videos_for_transcripts_job(overwrite, created_after, created_minutes): """Verify that get_youtube_videos_for_transcripts_job applies filters correctly""" video1 = VideoFactory.create(transcript="saved already") video2 = VideoFactory.create(transcript="") video3 = VideoFactory.create(transcript="saved already") video3.created_on = datetime(2019, 10, 1, tzinfo=pytz.utc) video3.save() video4 = VideoFactory.create(transcript="") video4.created_on = datetime(2019, 10, 1, tzinfo=pytz.utc) video4.save() video5 = VideoFactory.create(transcript="saved already") video5.created_on = datetime(2019, 10, 5, tzinfo=pytz.utc) video5.save() video6 = VideoFactory.create(transcript="") video6.created_on = datetime(2019, 10, 5, tzinfo=pytz.utc) video6.save() result = youtube.get_youtube_videos_for_transcripts_job( created_after=created_after, created_minutes=created_minutes, overwrite=overwrite, ) if overwrite: if created_after: assert list( result.order_by("id")) == [video1, video2, video5, video6] elif created_minutes: assert list(result.order_by("id")) == [video1, video2] else: assert list(result.order_by("id")) == [ video1, video2, video3, video4, video5, video6, ] else: if created_after: assert list(result.order_by("id")) == [video2, video6] elif created_minutes: assert list(result.order_by("id")) == [video2] else: assert list(result.order_by("id")) == [video2, video4, video6]
def test_load_playlist_user_list(mock_upsert_tasks, settings, user, exists, has_user_list, user_list_title): # pylint: disable=too-many-arguments """Test that load_playlist_user_list updates or create the user list""" settings.OPEN_VIDEO_USER_LIST_OWNER = user.username playlist = PlaylistFactory.create(has_user_list=has_user_list) videos = VideoFactory.create_batch(3) for idx, video in enumerate(videos): PlaylistVideo.objects.create(playlist=playlist, video=video, position=idx) prune_video = VideoFactory.create() video_content_type = ContentType.objects.get_for_model(Video) user_list = None if exists: user_list = UserListFactory.create(is_list=True, is_public=True, author=user) UserListItem.objects.create( user_list=user_list, content_type=video_content_type, object_id=prune_video.id, position=0, ) playlist.user_list = user_list playlist.save() else: assert playlist.user_list is None load_playlist_user_list(playlist, user_list_title) playlist.refresh_from_db() if has_user_list: if exists: assert playlist.user_list == user_list else: assert playlist.user_list is not None user_list = playlist.user_list assert user_list.author == user if user_list_title: assert user_list.title == user_list_title else: assert user_list.title == playlist.title assert user_list.privacy_level == PrivacyLevel.public.value assert user_list.list_type == ListType.LIST.value assert (UserListItem.objects.filter( user_list=user_list, content_type=video_content_type, object_id=prune_video.id, ).exists() is False) for video in videos: assert (UserListItem.objects.filter( user_list=user_list, content_type=video_content_type, object_id=video.id, ).exists() is True) mock_upsert_tasks.upsert_user_list.assert_called_once_with( user_list.id) else: assert playlist.user_list is None if exists: mock_upsert_tasks.delete_user_list.assert_called_once_with( user_list) else: mock_upsert_tasks.delete_user_list.assert_not_called()