aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorCody Robibero <cody@robibe.ro>2026-08-07 21:43:21 -0400
committerGitHub <noreply@github.com>2026-08-07 21:43:21 -0400
commit247ee406a986933d6b006a55605bb1881588f35d (patch)
tree07203c8d1af51845fb830b53ed9ce6f86fae1a99 /tests
parent2218f2931c5ae2f2c7c676d321c9d6803f066782 (diff)
parentd6da6906a4b3426f05c5bf4ffe8bab4b2bc78ce8 (diff)
Merge pull request #17571 from obiwantoby/perf/batch-people-dto
Batch people lookups when building item DTOs
Diffstat (limited to 'tests')
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Dto/DtoServiceImageInheritanceTests.cs50
1 files changed, 50 insertions, 0 deletions
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Dto/DtoServiceImageInheritanceTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Dto/DtoServiceImageInheritanceTests.cs
index 6b6240e116..d18f8c6cff 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Dto/DtoServiceImageInheritanceTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/Dto/DtoServiceImageInheritanceTests.cs
@@ -14,6 +14,7 @@ using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Trickplay;
using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Querying;
using Moq;
using Xunit;
@@ -155,6 +156,55 @@ public class DtoServiceImageInheritanceTests
libraryManager.Verify(x => x.GetArtist(It.IsAny<string>(), It.IsAny<DtoOptions>()), Times.Never);
}
+ [Fact]
+ public void GetBaseItemDtos_Items_ResolvePeopleFromBatch_WithoutPerItemLookup()
+ {
+ static MusicAlbum MakeAlbum() => new MusicAlbum
+ {
+ Id = Guid.NewGuid(),
+ Name = "Album",
+ ImageInfos = []
+ };
+
+ var albumOne = MakeAlbum();
+ var albumTwo = MakeAlbum();
+
+ var libraryManager = new Mock<ILibraryManager>();
+
+ // DtoService resolves people for every item in ONE batch (GetPeopleByItems) before the
+ // per-item loop. A regression to the per-item path would call GetPeople(BaseItem) once per
+ // item (the N+1); it is intentionally left unset so such a regression fails here.
+ libraryManager
+ .Setup(x => x.GetPeopleByItems(It.IsAny<IReadOnlyList<Guid>>()))
+ .Returns(new Dictionary<Guid, IReadOnlyList<PersonInfo>>
+ {
+ [albumOne.Id] = [new PersonInfo { ItemId = albumOne.Id, Name = "Some Actor", Type = PersonKind.Actor }],
+ [albumTwo.Id] = [new PersonInfo { ItemId = albumTwo.Id, Name = "Some Actor", Type = PersonKind.Actor }]
+ });
+
+ // AttachPeople still resolves each distinct name to its Person entity to attach images.
+ libraryManager
+ .Setup(x => x.GetPerson("Some Actor"))
+ .Returns(new Person { Id = Guid.NewGuid(), Name = "Some Actor" });
+
+ var dtoService = BuildDtoService(libraryManager);
+
+ var options = new DtoOptions(false) { Fields = [ItemFields.People] };
+ var dtos = dtoService.GetBaseItemDtos([albumOne, albumTwo], options);
+
+ Assert.Equal(2, dtos.Count);
+ foreach (var dto in dtos)
+ {
+ Assert.NotNull(dto.People);
+ Assert.Single(dto.People);
+ Assert.Equal("Some Actor", dto.People[0].Name);
+ }
+
+ // People are batched once for the whole set, never once per item.
+ libraryManager.Verify(x => x.GetPeopleByItems(It.IsAny<IReadOnlyList<Guid>>()), Times.Once);
+ libraryManager.Verify(x => x.GetPeople(It.IsAny<BaseItem>()), Times.Never);
+ }
+
private static DtoService BuildDtoService(BaseItem displayParent)
{
var libraryManager = new Mock<ILibraryManager>();