aboutsummaryrefslogtreecommitdiff
path: root/tests/Jellyfin.Server.Implementations.Tests/Library/MovieSimilarItemsProviderTests.cs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/Jellyfin.Server.Implementations.Tests/Library/MovieSimilarItemsProviderTests.cs')
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Library/MovieSimilarItemsProviderTests.cs104
1 files changed, 98 insertions, 6 deletions
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/MovieSimilarItemsProviderTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/MovieSimilarItemsProviderTests.cs
index 297f930205..421671b520 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Library/MovieSimilarItemsProviderTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/Library/MovieSimilarItemsProviderTests.cs
@@ -10,6 +10,7 @@ using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Server.Implementations.Tests.Item;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Configuration;
@@ -26,9 +27,14 @@ namespace Jellyfin.Server.Implementations.Tests.Library;
/// </summary>
public sealed class MovieSimilarItemsProviderTests : SqliteDbTestFixture
{
+ private static readonly Guid _movieLibraryId = Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa");
+ private static readonly Guid _movie4KLibraryId = Guid.Parse("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb");
+
private readonly MovieSimilarItemsProvider _provider;
+ private readonly Mock<ILibraryManager> _libraryManager = new();
private readonly User _user = new("test", "auth-provider", "reset-provider");
private readonly string _movieTypeName;
+ private readonly string _folderTypeName;
private readonly Guid _source = Guid.NewGuid();
private readonly Guid _sourceAlternate = Guid.NewGuid();
@@ -36,10 +42,19 @@ public sealed class MovieSimilarItemsProviderTests : SqliteDbTestFixture
private readonly Guid _similarAlternate = Guid.NewGuid();
private readonly Guid _unrelated = Guid.NewGuid();
+ // A second scenario, in two libraries and on a genre of its own, for the group whose primary the
+ // user may not be able to reach at all.
+ private readonly Guid _crossSource = Guid.NewGuid();
+ private readonly Guid _crossLibraryPrimary = Guid.NewGuid();
+ private readonly Guid _crossLibraryVersion = Guid.NewGuid();
+ private readonly Guid _sameLibraryPrimary = Guid.NewGuid();
+ private readonly Guid _sameLibraryVersion = Guid.NewGuid();
+
public MovieSimilarItemsProviderTests()
{
var itemTypeLookup = new ItemTypeLookup();
_movieTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.Movie]!;
+ _folderTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.Folder]!;
using (var context = CreateDbContext())
{
@@ -53,7 +68,7 @@ public sealed class MovieSimilarItemsProviderTests : SqliteDbTestFixture
CreateDbContextFactory(),
CreateBaseItemRepository(itemTypeLookup),
serverConfigurationManager.Object,
- new Mock<ILibraryManager>().Object);
+ _libraryManager.Object);
}
[Fact]
@@ -80,10 +95,52 @@ public sealed class MovieSimilarItemsProviderTests : SqliteDbTestFixture
Assert.DoesNotContain(_sourceAlternate, items);
}
- private async Task<List<Guid>> GetSimilarItemsAsync()
+ [Fact]
+ public async Task GetSimilarItems_UserWithoutThePrimarysLibrary_OffersTheVersion()
+ {
+ // The user may only open the library the 1080p version is in, so its primary is out of reach
+ // and the version is all that is left to stand in for the group.
+ RestrictUserTo(_movieLibraryId);
+
+ var items = await GetSimilarItemsAsync(_crossSource).ConfigureAwait(true);
+
+ Assert.Contains(_crossLibraryVersion, items);
+ Assert.DoesNotContain(_crossLibraryPrimary, items);
+ }
+
+ [Fact]
+ public async Task GetSimilarItems_UserWithBothLibraries_OffersThePrimaryOfTheGroupOnce()
+ {
+ RestrictUserTo(_movieLibraryId, _movie4KLibraryId);
+
+ var items = await GetSimilarItemsAsync(_crossSource).ConfigureAwait(true);
+
+ Assert.Contains(_crossLibraryPrimary, items);
+ Assert.DoesNotContain(_crossLibraryVersion, items);
+ }
+
+ [Fact]
+ public async Task GetSimilarItems_GroupMergedInsideOneLibrary_StillOffersOnlyThePrimary()
+ {
+ RestrictUserTo(_movieLibraryId, _movie4KLibraryId);
+
+ var items = await GetSimilarItemsAsync(_crossSource).ConfigureAwait(true);
+
+ Assert.Contains(_sameLibraryPrimary, items);
+ Assert.DoesNotContain(_sameLibraryVersion, items);
+ }
+
+ private void RestrictUserTo(params Guid[] libraryIds)
+ {
+ _libraryManager
+ .Setup(l => l.ConfigureUserAccess(It.IsAny<InternalItemsQuery>(), It.IsAny<User>()))
+ .Callback<InternalItemsQuery, User>((query, _) => query.TopParentIds = libraryIds);
+ }
+
+ private async Task<List<Guid>> GetSimilarItemsAsync(Guid? sourceId = null)
{
var results = await _provider.GetSimilarItemsAsync(
- new Movie { Id = _source, Name = "Source" },
+ new Movie { Id = sourceId ?? _source, Name = "Source" },
new SimilarItemsQuery { User = _user, Limit = 10, DtoOptions = new DtoOptions() },
CancellationToken.None).ConfigureAwait(false);
@@ -102,19 +159,52 @@ public sealed class MovieSimilarItemsProviderTests : SqliteDbTestFixture
var similarAlternate = AddMovie(context, _similarAlternate, "Similar 4K", primaryVersionId: _similar);
var unrelated = AddMovie(context, _unrelated, "Unrelated", primaryVersionId: null);
+ // The second scenario scores on a genre of its own, so it stays out of the results above.
+ var crossLibrary = CreateItemValue("Science Fiction", "science fiction");
+
+ AddLibrary(context, _movieLibraryId, "Movies");
+ AddLibrary(context, _movie4KLibraryId, "Movies-4K");
+
+ var crossSource = AddMovie(context, _crossSource, "Cross Source", primaryVersionId: null, libraryId: _movieLibraryId);
+
+ // The 4K version heads the group and lives in a library of its own.
+ var crossLibraryPrimary = AddMovie(context, _crossLibraryPrimary, "Coco 4K", primaryVersionId: null, libraryId: _movie4KLibraryId);
+ var crossLibraryVersion = AddMovie(context, _crossLibraryVersion, "Coco", primaryVersionId: _crossLibraryPrimary, libraryId: _movieLibraryId);
+
+ // A group merged inside one library, as a control.
+ var sameLibraryPrimary = AddMovie(context, _sameLibraryPrimary, "Up 4K", primaryVersionId: null, libraryId: _movieLibraryId);
+ var sameLibraryVersion = AddMovie(context, _sameLibraryVersion, "Up", primaryVersionId: _sameLibraryPrimary, libraryId: _movieLibraryId);
+
context.Users.Add(_user);
- context.ItemValues.AddRange(shared, other);
+ context.ItemValues.AddRange(shared, other, crossLibrary);
context.ItemValuesMap.AddRange(
CreateMap(source, shared),
CreateMap(sourceAlternate, shared),
CreateMap(similar, shared),
CreateMap(similarAlternate, shared),
- CreateMap(unrelated, other));
+ CreateMap(unrelated, other),
+ CreateMap(crossSource, crossLibrary),
+ CreateMap(crossLibraryPrimary, crossLibrary),
+ CreateMap(crossLibraryVersion, crossLibrary),
+ CreateMap(sameLibraryPrimary, crossLibrary),
+ CreateMap(sameLibraryVersion, crossLibrary));
context.SaveChanges();
}
- private BaseItemEntity AddMovie(JellyfinDbContext context, Guid id, string name, Guid? primaryVersionId)
+ private void AddLibrary(JellyfinDbContext context, Guid id, string name)
+ {
+ context.BaseItems.Add(new BaseItemEntity
+ {
+ Id = id,
+ Type = _folderTypeName,
+ Name = name,
+ Path = "/" + name,
+ IsFolder = true
+ });
+ }
+
+ private BaseItemEntity AddMovie(JellyfinDbContext context, Guid id, string name, Guid? primaryVersionId, Guid? libraryId = null)
{
var item = new BaseItemEntity
{
@@ -122,6 +212,8 @@ public sealed class MovieSimilarItemsProviderTests : SqliteDbTestFixture
Type = _movieTypeName,
Name = name,
SortName = name,
+ ParentId = libraryId,
+ TopParentId = libraryId,
MediaType = "Video",
IsMovie = true,
IsFolder = false,