1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.Data;
using Emby.Server.Implementations.Library.Search;
using Jellyfin.Database.Implementations;
using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Server.Implementations.Item;
using Jellyfin.Server.Implementations.Tests.Item;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Configuration;
using Microsoft.Extensions.Configuration;
using Moq;
using Xunit;
using BaseItemKind = Jellyfin.Data.Enums.BaseItemKind;
namespace Jellyfin.Server.Implementations.Tests.Library;
/// <summary>
/// Covers what <see cref="SqlSearchProvider"/> returns for a version group merged across two
/// libraries: the primary represents the group wherever it is visible, and the version stands in
/// for it for a user who cannot open the library the primary lives in.
/// </summary>
public sealed class SqlSearchProviderTests : 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 static readonly Guid _primaryId = Guid.Parse("cccccccc-cccc-cccc-cccc-cccccccccccc");
private static readonly Guid _versionId = Guid.Parse("dddddddd-dddd-dddd-dddd-dddddddddddd");
private readonly SqlSearchProvider _provider;
private readonly Mock<ILibraryManager> _libraryManager = new();
private readonly User _user = new("test", "auth-provider", "reset-provider");
public SqlSearchProviderTests()
{
var itemTypeLookup = new ItemTypeLookup();
var movieTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.Movie]!;
var folderTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.Folder]!;
using (var context = CreateDbContext())
{
context.Users.Add(_user);
context.BaseItems.Add(CreateLibrary(_movieLibraryId, folderTypeName, "Movies", "/movies"));
context.BaseItems.Add(CreateLibrary(_movie4KLibraryId, folderTypeName, "Movies-4K", "/movies-4k"));
context.BaseItems.Add(CreateMovie(_primaryId, movieTypeName, _movie4KLibraryId, null));
context.BaseItems.Add(CreateMovie(_versionId, movieTypeName, _movieLibraryId, _primaryId));
context.SaveChanges();
}
var userManager = new Mock<IUserManager>();
userManager.Setup(u => u.GetUserById(_user.Id)).Returns(_user);
var serverConfigurationManager = new Mock<IServerConfigurationManager>();
serverConfigurationManager.Setup(scm => scm.Configuration)
.Returns(new ServerConfiguration());
_provider = new SqlSearchProvider(
CreateDbContextFactory(),
itemTypeLookup,
_libraryManager.Object,
userManager.Object,
CreateBaseItemRepository(itemTypeLookup),
serverConfigurationManager.Object);
}
[Fact]
public async Task SearchAsync_UserWithoutThePrimarysLibrary_FindsTheVersion()
{
RestrictUserTo(_movieLibraryId);
var hits = await SearchAsync().ConfigureAwait(true);
Assert.Equal([_versionId], hits);
}
[Fact]
public async Task SearchAsync_UserWithBothLibraries_FindsThePrimaryOnce()
{
RestrictUserTo(_movieLibraryId, _movie4KLibraryId);
var hits = await SearchAsync().ConfigureAwait(true);
Assert.Equal([_primaryId], hits);
}
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>> SearchAsync()
{
var results = await _provider.SearchAsync(
new SearchProviderQuery { SearchTerm = "coco", UserId = _user.Id, Limit = 10 },
CancellationToken.None).ConfigureAwait(false);
return results.Select(r => r.ItemId).ToList();
}
private static BaseItemEntity CreateLibrary(Guid id, string typeName, string name, string path)
=> new()
{
Id = id,
Type = typeName,
Name = name,
Path = path,
IsFolder = true
};
private static BaseItemEntity CreateMovie(Guid id, string typeName, Guid libraryId, Guid? primaryVersionId)
=> new()
{
Id = id,
Type = typeName,
Name = "Coco",
CleanName = "coco",
SortName = "Coco",
MediaType = "Video",
IsMovie = true,
IsFolder = false,
IsVirtualItem = false,
ParentId = libraryId,
TopParentId = libraryId,
PresentationUniqueKey = (primaryVersionId ?? id).ToString("N"),
PrimaryVersionId = primaryVersionId
};
}
|