def test_load_playlists_unpublish(): """Test load_playlists when a video/playlist gets unpublished""" channel = VideoChannelFactory.create() userlist1 = UserListFactory.create() userlist2 = UserListFactory.create() playlist1 = PlaylistFactory.create(channel=channel, published=True, has_user_list=True, user_list=userlist1) playlist2 = PlaylistFactory.create(channel=channel, published=True, has_user_list=True, user_list=userlist2) playlist3 = PlaylistFactory.create(channel=channel, published=True, has_user_list=True, user_list=None) playlist4 = PlaylistFactory.create(channel=channel, published=True, has_user_list=False, user_list=None) playlists_data = [{ "playlist_id": playlist1.playlist_id, "platform": playlist1.platform, "videos": [], }] load_playlists(channel, playlists_data) playlist1.refresh_from_db() playlist2.refresh_from_db() playlist3.refresh_from_db() playlist4.refresh_from_db() assert playlist1.published is True assert playlist1.has_user_list is True assert playlist2.published is False assert playlist2.has_user_list is False assert playlist3.published is False assert playlist3.has_user_list is False assert playlist4.published is False assert playlist4.has_user_list is False assert UserList.objects.filter(id=userlist1.id).count() == 1 assert UserList.objects.filter(id=userlist2.id).count() == 0
def test_user_list_items_endpoint_update_item(client, user, is_author, mock_user_list_index): """Test userlistitems endpoint for updating UserListItem positions""" author = UserFactory.create() topics = CourseTopicFactory.create_batch(3) userlist = UserListFactory.create(author=author, privacy_level=PrivacyLevel.public.value, topics=topics) list_item_1 = UserListItemFactory.create(user_list=userlist, position=0) list_item_2 = UserListItemFactory.create(user_list=userlist, position=1) list_item_3 = UserListItemFactory.create(user_list=userlist, position=2) client.force_login(author if is_author else user) data = {"position": 0} resp = client.patch( reverse("userlistitems-detail", args=[userlist.id, list_item_3.id]), data=data, format="json", ) assert resp.status_code == (200 if is_author else 403) if resp.status_code == 200: assert resp.json()["position"] == 0 mock_user_list_index.upsert_user_list.assert_called_once_with( userlist.id) for idx, item in enumerate([list_item_3, list_item_1, list_item_2]): item.refresh_from_db() assert item.position == idx
def test_user_list_items_endpoint_delete_items(client, user, is_author, mock_user_list_index): """Test userlistitems endpoint for deleting UserListItems""" author = UserFactory.create() userlist = UserListFactory.create(author=author, privacy_level=PrivacyLevel.public.value) list_items = sorted( UserListItemFactory.create_batch(2, user_list=userlist), key=lambda item: item.id, ) client.force_login(author if is_author else user) resp = client.delete( reverse("userlistitems-detail", args=[userlist.id, list_items[0].id]), format="json", ) assert resp.status_code == (204 if is_author else 403) if resp.status_code == 204: mock_user_list_index.upsert_user_list_view.assert_called_with( userlist.id) client.delete( reverse("userlistitems-detail", args=[userlist.id, list_items[1].id]), format="json", ) mock_user_list_index.delete_user_list.assert_called_with(userlist)
def test_es_userlist_serializer_image_src(): """ Test that ESUserListSerializer uses 1st non-list list item image_src if the list image_src is None """ user_list = UserListFactory.create(image_src=None) UserListItemFactory.create(user_list=user_list, position=1, is_userlist=True) list_item_course = UserListItemFactory.create( user_list=user_list, position=2, is_course=True ) serialized = ESUserListSerializer(user_list).data assert_json_equal( serialized, { "author": user_list.author.id, "object_type": user_list.list_type, "list_type": user_list.list_type, "privacy_level": user_list.privacy_level, "id": user_list.id, "short_description": user_list.short_description, "title": user_list.title, "image_src": list_item_course.item.image_src, "topics": list(user_list.topics.values_list("name", flat=True)), "created": drf_datetime(user_list.created_on), "default_search_priority": 0, "minimum_price": 0, }, )
def test_es_userlist_serializer(list_type, privacy_level, user): """ Test that ESUserListSerializer correctly serializes a UserList object """ user_list = UserListFactory.create( list_type=list_type, privacy_level=privacy_level, author=user ) serialized = ESUserListSerializer(user_list).data assert_json_equal( serialized, { "author": user.id, "object_type": list_type, "list_type": list_type, "privacy_level": privacy_level, "id": user_list.id, "short_description": user_list.short_description, "title": user_list.title, "image_src": user_list.image_src.url, "topics": list(user_list.topics.values_list("name", flat=True)), "created": drf_datetime(user_list.created_on), "default_search_priority": 0, "minimum_price": 0, }, )
def test_favorites_serializer(): """ Test that the favorite serializer generic foreign key works and also rejects unexpected classes """ user = UserFactory.create() course = CourseFactory.create() bootcamp = BootcampFactory.create() user_list = UserListFactory.create(author=user) program = ProgramFactory.create() course_topic = CourseTopicFactory.create() favorite_item = FavoriteItem(user=user, item=course) serializer = FavoriteItemSerializer(favorite_item) assert serializer.data.get("content_data") == CourseSerializer(course).data favorite_item = FavoriteItem(user=user, item=bootcamp) serializer = FavoriteItemSerializer(favorite_item) assert serializer.data.get("content_data") == BootcampSerializer( bootcamp).data favorite_item = FavoriteItem(user=user, item=user_list) serializer = FavoriteItemSerializer(favorite_item) assert serializer.data.get("content_data") == UserListSerializer( user_list).data favorite_item = FavoriteItem(user=user, item=program) serializer = FavoriteItemSerializer(favorite_item) assert serializer.data.get("content_data") == ProgramSerializer( program).data favorite_item = FavoriteItem(user=user, item=course_topic) serializer = FavoriteItemSerializer(favorite_item) with pytest.raises(Exception): assert serializer.data.get("content_data").get("id") == course_topic.id
def test_upsert_user_list(mocker, list_type): """ Tests that upsert_user_list calls update_field_values_by_query with the right parameters """ patched_task = mocker.patch("search.tasks.upsert_user_list") user_list = UserListFactory.create(list_type=list_type) upsert_user_list(user_list.id) patched_task.delay.assert_called_once_with(user_list.id)
def test_delete_user_list(mocker, list_type): """Tests that deleting a UserList triggers a delete on a UserList document""" patched_delete_task = mocker.patch("search.task_helpers.delete_document") user_list = UserListFactory.create(list_type=list_type) delete_user_list(user_list) assert patched_delete_task.delay.called is True assert patched_delete_task.delay.call_args[0] == ( gen_user_list_id(user_list), USER_LIST_TYPE, )
def test_cascade_delete_listitems(kwargs): """ When a resource is deleted, UserListItems for that resource should be deleted """ user_list = UserListFactory.create() list_item = UserListItemFactory.create(user_list=user_list, **kwargs) assert user_list.items.count() == 1 resource = list_item.item resource.delete() assert user_list.items.count() == 0
def test_user_list_endpoint_get(client, is_public, is_author, user): """Test learning path endpoint""" author = UserFactory.create() user_list = UserListFactory.create( author=author, privacy_level=PrivacyLevel.public.value if is_public else PrivacyLevel.private.value, ) another_user_list = UserListFactory.create( author=UserFactory.create(), privacy_level=PrivacyLevel.public.value if is_public else PrivacyLevel.private.value, ) UserListItemFactory.create(user_list=user_list, position=1, is_bootcamp=True) UserListItemFactory.create(user_list=user_list, position=2) # Anonymous users should get no results resp = client.get(reverse("userlists-list")) assert resp.data.get("count") == 0 # Logged in user should get own lists client.force_login(author if is_author else user) resp = client.get(reverse("userlists-list")) assert resp.data.get("count") == (1 if is_author else 0) if is_author: assert "content_data" not in resp.data.get("results")[0] resp = client.get(reverse("userlists-detail", args=[user_list.id])) assert resp.status_code == (403 if not (is_public or is_author) else 200) if resp.status_code == 200: assert resp.data.get("title") == user_list.title assert len(resp.data.get("lists")) == 0 assert resp.data.get("item_count") == 2 # Logged in user should see other person's public list resp = client.get(reverse("userlists-detail", args=[another_user_list.id])) assert resp.status_code == (403 if not is_public else 200) if resp.status_code == 200: assert resp.data.get("title") == another_user_list.title
def test_favorite_lists_other_user(user_client, privacy_level): """Test favoriting and unfavoriting someone else's list""" is_public = privacy_level == PrivacyLevel.public.value userlist = UserListFactory.create(privacy_level=privacy_level) resp = user_client.post( reverse("userlists-detail", args=[userlist.id]) + "favorite/") assert resp.status_code == 200 if is_public else 403 resp = user_client.post( reverse("userlists-detail", args=[userlist.id]) + "unfavorite/") assert resp.status_code == 200 if is_public else 403
def test_generic_foreign_key_serializer_classes(factory, valid_type): """ Test that generic foreign key serializer properly accepts expected classes and rejects others """ userlist = UserListFactory.create() obj = getattr(factories, factory).create() list_item = UserListItem(user_list=userlist, item=obj) serializer = UserListItemSerializer(list_item) if valid_type: assert serializer.data.get("content_data").get("id") == obj.id else: with pytest.raises(Exception): assert serializer.data.get("content_data").get("id") == obj.id
def test_user_list_endpoint_delete(client, user, is_author, mock_user_list_index): """Test userlist endpoint for deleting a UserList""" author = UserFactory.create() userlist = UserListFactory.create(author=author, privacy_level=PrivacyLevel.public.value) client.force_login(author if is_author else user) resp = client.delete(reverse("userlists-detail", args=[userlist.id])) assert resp.status_code == (204 if is_author else 403) assert UserList.objects.filter(id=userlist.id).exists() is not is_author assert mock_user_list_index.delete_user_list.call_count == (1 if is_author else 0)
def test_userlist_object_permissions(mocker, user, is_public, is_author): """ HasUserListPermissions.has_object_permission should return correct permission depending on privacy level and author. """ userlist = UserListFactory.create( author=user, privacy_level=PrivacyLevel.public.value if is_public else PrivacyLevel.private.value, ) request = mocker.MagicMock( method="GET", user=(user if is_author else UserFactory.create())) assert HasUserListPermissions().has_object_permission( request, mocker.MagicMock(), userlist) is (is_public or is_author)
def test_userlistitems_permissions(mocker, user, is_safe, is_public, is_author): """ HasUserListItemPermissions.has_permission should return correct permission depending on privacy level, author, and request method. """ userlist = UserListFactory.create( author=user if is_author else UserFactory.create(), privacy_level=PrivacyLevel.public.value if is_public else PrivacyLevel.private.value, ) request = mocker.MagicMock(method="GET" if is_safe else "POST", user=user) view = mocker.MagicMock(kwargs={"parent_lookup_user_list_id": userlist.id}) assert HasUserListItemPermissions().has_permission( request, view) is (is_author or (is_safe and is_public))
def test_bootcamp_detail_endpoint_lists(user_client, user): """Test that author's list ids are included""" bootcamp = BootcampFactory.create() user_lists = UserListFactory.create_batch(2, author=user) list_items = sorted( [ UserListItemFactory.create(content_object=bootcamp, user_list=user_list) for user_list in user_lists ], key=lambda x: x.id, ) resp = user_client.get(reverse("bootcamps-detail", args=[bootcamp.id])) assert sorted(resp.data.get("lists"), key=lambda x: x["item_id"]) == [ MicroUserListItemSerializer(list_item).data for list_item in list_items ]
def test_userlistitem_serializer_validation(content_type, factory, valid_type, object_exists): """ Test that the UserListItemSerializer validates content_type and object correctly """ userlist = UserListFactory.create() # pylint:disable=redefined-builtin object_id = getattr(factories, factory).create().id if object_exists else 1_001_001 data = { "content_type": content_type, "object_id": object_id, "user_list": userlist.id, } serializer = UserListItemSerializer(data=data) assert serializer.is_valid() == (valid_type and object_exists)
def test_user_list_items_endpoint_update_items_wrong_list(client, user): """Verify that trying an update via userlistitems api in wrong list fails""" userlist = UserListFactory.create(author=user, privacy_level=PrivacyLevel.public.value) list_item_incorrect = UserListItemFactory.create() client.force_login(user) data = {"id": list_item_incorrect.id, "position": 44} resp = client.patch( reverse("userlistitems-detail", args=[userlist.id, list_item_incorrect.id]), data=data, format="json", ) assert resp.status_code == 404
def test_userlist_favorite_permissions(mocker, user, is_public, is_author, action): """ HasUserListPermissions.has_object_permission should return correct permission depending on privacy level and author when favoriting or unfavoriting. """ userlist = UserListFactory.create( author=user, privacy_level=PrivacyLevel.public.value if is_public else PrivacyLevel.private.value, ) request = mocker.MagicMock( method="POST", user=(user if is_author else UserFactory.create())) assert HasUserListPermissions().has_object_permission( request, mocker.MagicMock(action=action), userlist) is ((is_public and "favorite" in action) or is_author)
def test_user_list_items_endpoint_create_item_bad_data(client, user): """Test userlistitems endpoint for creating a UserListItem""" userlist = UserListFactory.create(author=user, privacy_level=PrivacyLevel.public.value) course = CourseFactory.create() client.force_login(user) data = {"content_type": "bad_content", "object_id": course.id} resp = client.post(reverse("userlistitems-list", args=[userlist.id]), data=data, format="json") assert resp.status_code == 400 assert resp.json() == { "non_field_errors": ["Incorrect object type bad_content"], "error_type": "ValidationError", }
def test_user_list_items_endpoint_create_item(client, user, is_author, mock_user_list_index): """Test userlistitems endpoint for creating a UserListItem""" author = UserFactory.create() userlist = UserListFactory.create(author=author, privacy_level=PrivacyLevel.public.value) course = CourseFactory.create() client.force_login(author if is_author else user) data = {"content_type": "course", "object_id": course.id} resp = client.post(reverse("userlistitems-list", args=[userlist.id]), data=data, format="json") assert resp.status_code == (201 if is_author else 403) if resp.status_code == 201: assert resp.json().get("object_id") == course.id mock_user_list_index.upsert_user_list.assert_called_once_with( userlist.id)
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_user_list_endpoint_patch(client, user, mock_user_list_index, update_topics): """Test userlist endpoint for updating a UserList""" [original_topic, new_topic] = CourseTopicFactory.create_batch(2) userlist = UserListFactory.create(author=user, title="Title 1", topics=[original_topic]) UserListItemFactory.create(user_list=userlist) client.force_login(user) data = {"title": "Title 2"} if update_topics: data["topics"] = [new_topic.id] resp = client.patch(reverse("userlists-detail", args=[userlist.id]), data=data, format="json") assert resp.status_code == 200 assert UserList.objects.get(id=userlist.id).title == "Title 2" assert resp.data["topics"][0]["id"] == (new_topic.id if update_topics else original_topic.id) mock_user_list_index.upsert_user_list.assert_called_once_with(userlist.id)
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()