aboutsummaryrefslogtreecommitdiff
path: root/tests/Jellyfin.Controller.Tests
diff options
context:
space:
mode:
authorShadowghost <Shadowghost@users.noreply.github.com>2026-09-15 11:15:46 -0400
committerCody Robibero <cody@robibe.ro>2026-09-15 11:15:46 -0400
commit006ecadbe041ea422b34adf6a3fcf6638d189a70 (patch)
treec845d30aafd6cb23bf2e41dd955712db0f641ce4 /tests/Jellyfin.Controller.Tests
parent65bc888b07a25d1883d4d0a2f55a7f3e1ac35c87 (diff)
Backport pull request #17881 from jellyfin/release-12.z
Fix /UserViews exhausting memory and reporting random child counts Original-merge: a838a06aa51eac388a76e9e6421f1a80873c417b Merged-by: crobibero <cody@robibe.ro> Backported-by: Cody Robibero <cody@robibe.ro>
Diffstat (limited to 'tests/Jellyfin.Controller.Tests')
-rw-r--r--tests/Jellyfin.Controller.Tests/Entities/PlaylistTests.cs84
1 files changed, 84 insertions, 0 deletions
diff --git a/tests/Jellyfin.Controller.Tests/Entities/PlaylistTests.cs b/tests/Jellyfin.Controller.Tests/Entities/PlaylistTests.cs
new file mode 100644
index 0000000000..70da5eafe5
--- /dev/null
+++ b/tests/Jellyfin.Controller.Tests/Entities/PlaylistTests.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Linq;
+using Jellyfin.Data;
+using Jellyfin.Data.Enums;
+using Jellyfin.Database.Implementations.Entities;
+using Jellyfin.Database.Implementations.Enums;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Playlists;
+using MediaBrowser.Model.Querying;
+using Moq;
+using Xunit;
+
+namespace Jellyfin.Controller.Tests.Entities;
+
+public class PlaylistTests
+{
+ [Fact]
+ public void IsVisible_PlaylistWithNothingLeftInIt_IsHidden()
+ {
+ // The SQL parental filter hides a container whose every member is blocked, so a listing
+ // built in memory has to reach the same answer.
+ var blocked = new Movie { Id = Guid.NewGuid(), Name = "Movie" };
+ SetupLibrary(blocked);
+
+ Assert.False(BuildPlaylist(blocked).IsVisible(BuildRestrictedUser()));
+ }
+
+ [Fact]
+ public void IsVisible_PlaylistWithOneAllowedItem_StaysVisible()
+ {
+ var blocked = new Movie { Id = Guid.NewGuid(), Name = "Movie" };
+ var allowed = new Audio { Id = Guid.NewGuid(), Name = "Song" };
+ SetupLibrary(blocked, allowed);
+
+ Assert.True(BuildPlaylist(blocked, allowed).IsVisible(BuildRestrictedUser()));
+ }
+
+ [Fact]
+ public void IsVisible_UnrestrictedUser_LeavesTheItemsUnresolved()
+ {
+ var blocked = new Movie { Id = Guid.NewGuid(), Name = "Movie" };
+ var libraryManager = SetupLibrary(blocked);
+ var user = new User("user", "auth-provider", "reset-provider");
+
+ Assert.True(BuildPlaylist(blocked).IsVisible(user));
+
+ // Resolving a playlist's items is a query per playlist; nothing may run it for a user no
+ // rating keeps anything from.
+ libraryManager.Verify(x => x.GetItemList(It.IsAny<InternalItemsQuery>()), Times.Never);
+ }
+
+ private static Mock<ILibraryManager> SetupLibrary(params BaseItem[] items)
+ {
+ var libraryManager = new Mock<ILibraryManager>();
+ libraryManager
+ .Setup(x => x.GetItemList(It.IsAny<InternalItemsQuery>()))
+ .Returns(items);
+ BaseItem.LibraryManager = libraryManager.Object;
+
+ return libraryManager;
+ }
+
+ private static Playlist BuildPlaylist(params BaseItem[] items)
+ {
+ // An empty path keeps the playlist out of the shared-playlist branch.
+ return new Playlist
+ {
+ Id = Guid.NewGuid(),
+ Name = "Playlist",
+ LinkedChildren = items.Select(LinkedChild.Create).ToArray()
+ };
+ }
+
+ private static User BuildRestrictedUser()
+ {
+ var user = new User("user", "auth-provider", "reset-provider") { MaxParentalRatingScore = 5 };
+ user.SetPreference(PreferenceKind.BlockUnratedItems, new[] { UnratedItem.Movie });
+
+ return user;
+ }
+}