aboutsummaryrefslogtreecommitdiff
path: root/tests/Jellyfin.Server.Implementations.Tests/Library/SqlSearchProviderTests.cs
blob: 5aa770b9b3b1faa31c9ad495cdbce2c49baf087a (plain)
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
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.Entities;
using MediaBrowser.Controller.Library;
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);

        _provider = new SqlSearchProvider(
            CreateDbContextFactory(),
            itemTypeLookup,
            _libraryManager.Object,
            userManager.Object,
            CreateBaseItemRepository(itemTypeLookup));
    }

    [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
        };
}