diff options
| author | Shadowghost <Ghost_of_Stone@web.de> | 2026-08-12 07:42:29 +0200 |
|---|---|---|
| committer | Shadowghost <Ghost_of_Stone@web.de> | 2026-08-12 08:15:55 +0200 |
| commit | 9ae6ffe441586764554ea0e347b540365f069a00 (patch) | |
| tree | a11513b8b4f459559efce23e09760f9d3c7081a1 | |
| parent | fa7fdf58840567c07e85ffb00be4318e12fd021e (diff) | |
Share the SQLite fixture across the item tests
8 files changed, 115 insertions, 288 deletions
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Item/AlternateVersionQueryTranslationTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Item/AlternateVersionQueryTranslationTests.cs index b7fca74310..2dbcd41a41 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Item/AlternateVersionQueryTranslationTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Item/AlternateVersionQueryTranslationTests.cs @@ -1,14 +1,9 @@ -#pragma warning disable RS0030 // Do not use banned APIs: Guid == is required inside EF expression trees to mirror the production query shapes. +#pragma warning disable RS0030 // Do not use banned APIs: Guid == is required inside EF expression trees to mirror the production query shapes. using System; using System.Linq; using Jellyfin.Database.Implementations; using Jellyfin.Database.Implementations.Entities; -using Jellyfin.Database.Implementations.Locking; -using Jellyfin.Database.Providers.Sqlite; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging.Abstractions; using Xunit; namespace Jellyfin.Server.Implementations.Tests.Item; @@ -18,22 +13,10 @@ namespace Jellyfin.Server.Implementations.Tests.Item; /// (BaseItemRepository.TranslateQuery) and the DatePlayed ordering (OrderMapper) translate /// and evaluate correctly on the SQLite provider. /// </summary> -public sealed class AlternateVersionQueryTranslationTests : IDisposable +public sealed class AlternateVersionQueryTranslationTests : SqliteDbTestFixture { - private readonly SqliteConnection _connection; - private readonly DbContextOptions<JellyfinDbContext> _dbOptions; - public AlternateVersionQueryTranslationTests() { - _connection = new SqliteConnection("Data Source=:memory:"); - _connection.Open(); - - _dbOptions = new DbContextOptionsBuilder<JellyfinDbContext>() - .UseSqlite(_connection) - .Options; - - using var ctx = CreateDbContext(); - ctx.Database.EnsureCreated(); } [Fact] @@ -220,18 +203,4 @@ public sealed class AlternateVersionQueryTranslationTests : IDisposable ctx.SaveChanges(); return (user.Id, primary.Id, versionA.Id, versionB.Id); } - - private JellyfinDbContext CreateDbContext() - { - return new JellyfinDbContext( - _dbOptions, - NullLogger<JellyfinDbContext>.Instance, - new SqliteDatabaseProvider(null!, NullLogger<SqliteDatabaseProvider>.Instance), - new NoLockBehavior(NullLogger<NoLockBehavior>.Instance)); - } - - public void Dispose() - { - _connection.Dispose(); - } } diff --git a/tests/Jellyfin.Server.Implementations.Tests/Item/BaseItemRepositoryByNameTotalCountTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Item/BaseItemRepositoryByNameTotalCountTests.cs index f675621e21..7dbaea2fb5 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Item/BaseItemRepositoryByNameTotalCountTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Item/BaseItemRepositoryByNameTotalCountTests.cs @@ -1,19 +1,10 @@ -using System; +using System; using System.Linq; using Emby.Server.Implementations.Data; using Jellyfin.Database.Implementations; using Jellyfin.Database.Implementations.Entities; -using Jellyfin.Database.Implementations.Locking; -using Jellyfin.Database.Providers.Sqlite; using Jellyfin.Server.Implementations.Item; -using MediaBrowser.Controller; -using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Configuration; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging.Abstractions; -using Moq; using Xunit; using BaseItemKind = Jellyfin.Data.Enums.BaseItemKind; @@ -24,46 +15,16 @@ namespace Jellyfin.Server.Implementations.Tests.Item; /// <c>GetItemValues</c>. A query without a <c>Limit</c> used to have its total record count /// silently disabled, so callers got a populated <c>Items</c> array next to a zero total. /// </summary> -public sealed class BaseItemRepositoryByNameTotalCountTests : IDisposable +public sealed class BaseItemRepositoryByNameTotalCountTests : SqliteDbTestFixture { - private readonly SqliteConnection _connection; - private readonly DbContextOptions<JellyfinDbContext> _dbOptions; private readonly BaseItemRepository _repository; private readonly ItemTypeLookup _itemTypeLookup; public BaseItemRepositoryByNameTotalCountTests() { - _connection = new SqliteConnection("Data Source=:memory:"); - _connection.Open(); - - _dbOptions = new DbContextOptionsBuilder<JellyfinDbContext>() - .UseSqlite(_connection) - .Options; - - using (var ctx = CreateDbContext()) - { - ctx.Database.EnsureCreated(); - } - - var factory = new Mock<IDbContextFactory<JellyfinDbContext>>(); - factory.Setup(f => f.CreateDbContext()).Returns(CreateDbContext); - _itemTypeLookup = new ItemTypeLookup(); - var serverConfigurationManager = new Mock<IServerConfigurationManager>(); - serverConfigurationManager.Setup(c => c.Configuration).Returns(new ServerConfiguration()); - - _repository = new BaseItemRepository( - factory.Object, - new Mock<IServerApplicationHost>().Object, - _itemTypeLookup, - serverConfigurationManager.Object, - NullLogger<BaseItemRepository>.Instance); - } - - public void Dispose() - { - _connection.Dispose(); + _repository = CreateBaseItemRepository(_itemTypeLookup); } [Fact] @@ -187,13 +148,4 @@ public sealed class BaseItemRepositoryByNameTotalCountTests : IDisposable ctx.SaveChanges(); } - - private JellyfinDbContext CreateDbContext() - { - return new JellyfinDbContext( - _dbOptions, - NullLogger<JellyfinDbContext>.Instance, - new SqliteDatabaseProvider(null!, NullLogger<SqliteDatabaseProvider>.Instance), - new NoLockBehavior(NullLogger<NoLockBehavior>.Instance)); - } } diff --git a/tests/Jellyfin.Server.Implementations.Tests/Item/BaseItemRepositoryGroupingTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Item/BaseItemRepositoryGroupingTests.cs index 083f725db9..5dd648a2b8 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Item/BaseItemRepositoryGroupingTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Item/BaseItemRepositoryGroupingTests.cs @@ -1,66 +1,27 @@ -using System; +using System; using System.Linq; using Emby.Server.Implementations.Data; using Jellyfin.Database.Implementations; using Jellyfin.Database.Implementations.Entities; -using Jellyfin.Database.Implementations.Locking; -using Jellyfin.Database.Providers.Sqlite; using Jellyfin.Server.Implementations.Item; -using MediaBrowser.Controller; -using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging.Abstractions; -using Moq; using Xunit; using BaseItemKind = Jellyfin.Data.Enums.BaseItemKind; namespace Jellyfin.Server.Implementations.Tests.Item; -public sealed class BaseItemRepositoryGroupingTests : IDisposable +public sealed class BaseItemRepositoryGroupingTests : SqliteDbTestFixture { - private readonly SqliteConnection _connection; - private readonly DbContextOptions<JellyfinDbContext> _dbOptions; private readonly BaseItemRepository _repository; private readonly string _movieTypeName; public BaseItemRepositoryGroupingTests() { - _connection = new SqliteConnection("Data Source=:memory:"); - _connection.Open(); - - _dbOptions = new DbContextOptionsBuilder<JellyfinDbContext>() - .UseSqlite(_connection) - .Options; - - using (var ctx = CreateDbContext()) - { - ctx.Database.EnsureCreated(); - } - - var factory = new Mock<IDbContextFactory<JellyfinDbContext>>(); - factory.Setup(f => f.CreateDbContext()).Returns(CreateDbContext); - var itemTypeLookup = new ItemTypeLookup(); _movieTypeName = itemTypeLookup.BaseItemKindNames[BaseItemKind.Movie]; - var serverConfigurationManager = new Mock<IServerConfigurationManager>(); - serverConfigurationManager.Setup(c => c.Configuration).Returns(new ServerConfiguration()); - - _repository = new BaseItemRepository( - factory.Object, - new Mock<IServerApplicationHost>().Object, - itemTypeLookup, - serverConfigurationManager.Object, - NullLogger<BaseItemRepository>.Instance); - } - - public void Dispose() - { - _connection.Dispose(); + _repository = CreateBaseItemRepository(itemTypeLookup); } [Fact] @@ -132,13 +93,4 @@ public sealed class BaseItemRepositoryGroupingTests : IDisposable IsVirtualItem = false }; } - - private JellyfinDbContext CreateDbContext() - { - return new JellyfinDbContext( - _dbOptions, - NullLogger<JellyfinDbContext>.Instance, - new SqliteDatabaseProvider(null!, NullLogger<SqliteDatabaseProvider>.Instance), - new NoLockBehavior(NullLogger<NoLockBehavior>.Instance)); - } } diff --git a/tests/Jellyfin.Server.Implementations.Tests/Item/BaseItemRepositoryStreamFilterTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Item/BaseItemRepositoryStreamFilterTests.cs index 717085b440..3407e2130b 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Item/BaseItemRepositoryStreamFilterTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Item/BaseItemRepositoryStreamFilterTests.cs @@ -1,37 +1,25 @@ -using System; +using System; using System.Linq; using Emby.Server.Implementations.Data; using Jellyfin.Database.Implementations; using Jellyfin.Database.Implementations.Entities; -using Jellyfin.Database.Implementations.Locking; -using Jellyfin.Database.Providers.Sqlite; using Jellyfin.Server.Implementations.Item; -using MediaBrowser.Controller; -using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Configuration; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging.Abstractions; -using Moq; using Xunit; using LinkedChildType = Jellyfin.Database.Implementations.Entities.LinkedChildType; namespace Jellyfin.Server.Implementations.Tests.Item; /// <summary> -/// Covers the filters that resolve "folders with a matching descendant" through -/// <see cref="DescendantQueryHelper.GetFolderIdsMatching"/>, both in their positive and their -/// negated form, so the sub-selects they build stay translatable on the SQLite provider. +/// Covers the filters resolving "folders with a matching descendant" through +/// <see cref="DescendantQueryHelper.GetFolderIdsMatching"/>, positive and negated. /// </summary> -public sealed class BaseItemRepositoryStreamFilterTests : IDisposable +public sealed class BaseItemRepositoryStreamFilterTests : SqliteDbTestFixture { private const string FolderType = "MediaBrowser.Controller.Entities.Folder"; private const string BoxSetType = "MediaBrowser.Controller.Entities.Movies.BoxSet"; private const string MovieType = "MediaBrowser.Controller.Entities.Movies.Movie"; - private readonly SqliteConnection _connection; - private readonly DbContextOptions<JellyfinDbContext> _dbOptions; private readonly BaseItemRepository _repository; private readonly Guid _library = Guid.NewGuid(); @@ -43,35 +31,14 @@ public sealed class BaseItemRepositoryStreamFilterTests : IDisposable public BaseItemRepositoryStreamFilterTests() { - _connection = new SqliteConnection("Data Source=:memory:"); - _connection.Open(); - - _dbOptions = new DbContextOptionsBuilder<JellyfinDbContext>() - .UseSqlite(_connection) - .Options; - using (var ctx = CreateDbContext()) { - ctx.Database.EnsureCreated(); Seed(ctx); } - var factory = new Mock<IDbContextFactory<JellyfinDbContext>>(); - factory.Setup(f => f.CreateDbContext()).Returns(CreateDbContext); - - var serverConfigurationManager = new Mock<IServerConfigurationManager>(); - serverConfigurationManager.Setup(c => c.Configuration).Returns(new ServerConfiguration()); - - _repository = new BaseItemRepository( - factory.Object, - new Mock<IServerApplicationHost>().Object, - new ItemTypeLookup(), - serverConfigurationManager.Object, - NullLogger<BaseItemRepository>.Instance); + _repository = CreateBaseItemRepository(new ItemTypeLookup()); } - public void Dispose() => _connection.Dispose(); - [Fact] public void HasSubtitles_MatchesTheItemAndItsParentFolder() { @@ -115,7 +82,6 @@ public sealed class BaseItemRepositoryStreamFilterTests : IDisposable { var ids = _repository.GetItemIdsList(new InternalItemsQuery { HasSubtitles = true }); - // The collection links the series, and the subtitles hang off the series' episode. Assert.Contains(_linkedSeries, ids); Assert.Contains(_collection, ids); } @@ -214,11 +180,4 @@ public sealed class BaseItemRepositoryStreamFilterTests : IDisposable context.SaveChanges(); } - - private JellyfinDbContext CreateDbContext() - => new JellyfinDbContext( - _dbOptions, - NullLogger<JellyfinDbContext>.Instance, - new SqliteDatabaseProvider(null!, NullLogger<SqliteDatabaseProvider>.Instance), - new NoLockBehavior(NullLogger<NoLockBehavior>.Instance)); } diff --git a/tests/Jellyfin.Server.Implementations.Tests/Item/DescendantQueryHelperTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Item/DescendantQueryHelperTests.cs index fae2dd0628..6cd31d9243 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Item/DescendantQueryHelperTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Item/DescendantQueryHelperTests.cs @@ -1,14 +1,10 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Jellyfin.Database.Implementations; using Jellyfin.Database.Implementations.Entities; -using Jellyfin.Database.Implementations.Locking; using Jellyfin.Database.Implementations.MatchCriteria; -using Jellyfin.Database.Providers.Sqlite; -using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging.Abstractions; using Xunit; namespace Jellyfin.Server.Implementations.Tests.Item; @@ -17,31 +13,18 @@ namespace Jellyfin.Server.Implementations.Tests.Item; /// Verifies the descendant traversals against the SQLite provider: the sets they resolve, and that /// they stay sub-selects instead of inlining every descendant id into the statement. /// </summary> -public sealed class DescendantQueryHelperTests : IDisposable +public sealed class DescendantQueryHelperTests : SqliteDbTestFixture { private const string FolderType = "MediaBrowser.Controller.Entities.Folder"; private const string BoxSetType = "MediaBrowser.Controller.Entities.Movies.BoxSet"; private const string MovieType = "MediaBrowser.Controller.Entities.Movies.Movie"; private readonly Dictionary<Guid, int> _linkCounters = new(); - private readonly SqliteConnection _connection; - private readonly DbContextOptions<JellyfinDbContext> _dbOptions; public DescendantQueryHelperTests() { - _connection = new SqliteConnection("Data Source=:memory:"); - _connection.Open(); - - _dbOptions = new DbContextOptionsBuilder<JellyfinDbContext>() - .UseSqlite(_connection) - .Options; - - using var ctx = CreateDbContext(); - ctx.Database.EnsureCreated(); } - public void Dispose() => _connection.Dispose(); - [Fact] public void GetAllDescendantIds_Hierarchy_ReturnsEveryLevelWithoutTheParent() { @@ -95,7 +78,6 @@ public sealed class DescendantQueryHelperTests : IDisposable { var descendants = DescendantQueryHelper.GetAllDescendantIds(ctx, boxSet).ToHashSet(); - // The link reaches the series, and the series' own closure reaches the episode. Assert.Contains(series, descendants); Assert.Contains(episode, descendants); } @@ -117,7 +99,7 @@ public sealed class DescendantQueryHelperTests : IDisposable AddLink(ctx, outer, inner); AddLink(ctx, inner, movie); - // Cycle back to the outer set: the traversal must not spin on it. + // The traversal must not spin on this cycle. AddLink(ctx, inner, outer); ctx.SaveChanges(); } @@ -179,8 +161,8 @@ public sealed class DescendantQueryHelperTests : IDisposable AddItem(ctx, boxSet, BoxSetType, isFolder: true); AddItem(ctx, linkedMovie, MovieType); - // How production writes it: an item carries its own chain plus its collection folder, but - // not the user root above that folder - so one hop from the user root stops there. + // An item carries its own chain plus its collection folder, but not the user root above + // it, so one hop from the user root stops at the collection folder. AddAncestors(ctx, collectionFolder, userRoot); AddAncestors(ctx, series, collectionFolder); AddAncestors(ctx, episode, series, collectionFolder); @@ -264,7 +246,6 @@ public sealed class DescendantQueryHelperTests : IDisposable AddLink(ctx, boxSet, series); AddStream(ctx, episode, MediaStreamTypeEntity.Subtitle); - // A second collection, over an item without subtitles, must not be picked up. AddFolder(ctx, otherLibrary); AddItem(ctx, otherBoxSet, BoxSetType, isFolder: true); AddItem(ctx, silentMovie, MovieType); @@ -302,7 +283,7 @@ public sealed class DescendantQueryHelperTests : IDisposable AddLink(ctx, outer, inner); AddLink(ctx, inner, movie); - // Cycle back to the outer set: resolving the link parents must not spin on it. + // Resolving the link parents must not spin on this cycle. AddLink(ctx, inner, outer); AddStream(ctx, movie, MediaStreamTypeEntity.Subtitle); @@ -337,8 +318,7 @@ public sealed class DescendantQueryHelperTests : IDisposable AddFolder(ctx, series); AddItem(ctx, episode, MovieType); - // How production writes it: an item carries its own chain plus its collection folder, but - // not the user root above that folder - so the closure is not transitive at this seam. + // The closure is not transitive at this seam: no item records the user root. AddAncestors(ctx, episode, series, collectionFolder); AddAncestors(ctx, series, collectionFolder); AddAncestors(ctx, collectionFolder, userRoot); @@ -419,8 +399,8 @@ public sealed class DescendantQueryHelperTests : IDisposable var smallSql = CountingQuery(ctx, small).ToQueryString(); var largeSql = CountingQuery(ctx, large).ToQueryString(); - // Reading the ids into memory and passing them back as AsQueryable() makes EF inline one - // literal per descendant, which is what made a large library allocate megabytes per call. + // Reading the ids into memory and handing them back as AsQueryable() makes EF inline one + // literal per descendant, which is what allocated megabytes per call. Assert.Equal(smallSql.Length, largeSql.Length); Assert.Contains("AncestorIds", smallSql, StringComparison.Ordinal); Assert.Equal(10, CountingQuery(ctx, small).Count()); @@ -505,11 +485,4 @@ public sealed class DescendantQueryHelperTests : IDisposable SortOrder = sortOrder }); } - - private JellyfinDbContext CreateDbContext() - => new JellyfinDbContext( - _dbOptions, - NullLogger<JellyfinDbContext>.Instance, - new SqliteDatabaseProvider(null!, NullLogger<SqliteDatabaseProvider>.Instance), - new NoLockBehavior(NullLogger<NoLockBehavior>.Instance)); } diff --git a/tests/Jellyfin.Server.Implementations.Tests/Item/ItemPersistenceOwnedRowTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Item/ItemPersistenceOwnedRowTests.cs index 6324706452..9b78a609ab 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Item/ItemPersistenceOwnedRowTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Item/ItemPersistenceOwnedRowTests.cs @@ -1,51 +1,29 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; using Jellyfin.Database.Implementations; -using Jellyfin.Database.Implementations.Locking; -using Jellyfin.Database.Providers.Sqlite; using Jellyfin.Server.Implementations.Item; -using MediaBrowser.Common.Configuration; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging.Abstractions; using Moq; using Xunit; namespace Jellyfin.Server.Implementations.Tests.Item; -public sealed class ItemPersistenceOwnedRowTests : IDisposable +public sealed class ItemPersistenceOwnedRowTests : SqliteDbTestFixture { - private readonly SqliteConnection _connection; - private readonly DbContextOptions<JellyfinDbContext> _dbOptions; private readonly ItemPersistenceService _service; - private readonly IApplicationPaths _applicationPaths; private readonly ILibraryManager? _previousLibraryManager; private readonly IServerConfigurationManager? _previousConfigurationManager; public ItemPersistenceOwnedRowTests() { - _applicationPaths = new Mock<IApplicationPaths>().Object; - - _connection = new SqliteConnection("Data Source=:memory:"); - _connection.Open(); - - _dbOptions = new DbContextOptionsBuilder<JellyfinDbContext>() - .UseSqlite(_connection) - .Options; - - using (var ctx = CreateDbContext()) - { - ctx.Database.EnsureCreated(); - } - // BaseItem resolves these through process-wide statics; restored in Dispose. _previousLibraryManager = BaseItem.LibraryManager; _previousConfigurationManager = BaseItem.ConfigurationManager; @@ -59,20 +37,17 @@ public sealed class ItemPersistenceOwnedRowTests : IDisposable configurationManager.Setup(c => c.Configuration).Returns(new ServerConfiguration()); BaseItem.ConfigurationManager = configurationManager.Object; - var factory = new Mock<IDbContextFactory<JellyfinDbContext>>(); - factory.Setup(f => f.CreateDbContext()).Returns(CreateDbContext); - _service = new ItemPersistenceService( - factory.Object, + CreateDbContextFactory(), new Mock<IServerApplicationHost>().Object, NullLogger<ItemPersistenceService>.Instance); } - public void Dispose() + protected override void Dispose(bool disposing) { BaseItem.LibraryManager = _previousLibraryManager!; BaseItem.ConfigurationManager = _previousConfigurationManager!; - _connection.Dispose(); + base.Dispose(disposing); } [Fact] @@ -140,10 +115,4 @@ public sealed class ItemPersistenceOwnedRowTests : IDisposable book.SetImage(new ItemImageInfo { Path = "/img/primary.jpg", Type = ImageType.Primary }, 0); return book; } - - private JellyfinDbContext CreateDbContext() => new( - _dbOptions, - NullLogger<JellyfinDbContext>.Instance, - new SqliteDatabaseProvider(_applicationPaths, NullLogger<SqliteDatabaseProvider>.Instance), - new NoLockBehavior(NullLogger<NoLockBehavior>.Instance)); } diff --git a/tests/Jellyfin.Server.Implementations.Tests/Item/PeopleRepositoryUpdatePeopleTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Item/PeopleRepositoryUpdatePeopleTests.cs index 70d8e1f833..83465245fa 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Item/PeopleRepositoryUpdatePeopleTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Item/PeopleRepositoryUpdatePeopleTests.cs @@ -1,45 +1,30 @@ -using System; +using System; using System.Linq; using Emby.Server.Implementations.Data; using Jellyfin.Data.Enums; using Jellyfin.Database.Implementations; using Jellyfin.Database.Implementations.Entities; -using Jellyfin.Database.Implementations.Locking; -using Jellyfin.Database.Providers.Sqlite; using Jellyfin.Server.Implementations.Item; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Persistence; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging.Abstractions; using Moq; using Xunit; using BaseItemKind = Jellyfin.Data.Enums.BaseItemKind; namespace Jellyfin.Server.Implementations.Tests.Item; -public sealed class PeopleRepositoryUpdatePeopleTests : IDisposable +public sealed class PeopleRepositoryUpdatePeopleTests : SqliteDbTestFixture { private static readonly Guid _itemId = Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"); - private readonly SqliteConnection _connection; - private readonly DbContextOptions<JellyfinDbContext> _dbOptions; private readonly PeopleRepository _repository; public PeopleRepositoryUpdatePeopleTests() { - _connection = new SqliteConnection("Data Source=:memory:"); - _connection.Open(); - - _dbOptions = new DbContextOptionsBuilder<JellyfinDbContext>() - .UseSqlite(_connection) - .Options; - var itemTypeLookup = new ItemTypeLookup(); using (var ctx = CreateDbContext()) { - ctx.Database.EnsureCreated(); ctx.BaseItems.Add(new BaseItemEntity { Id = _itemId, @@ -53,20 +38,12 @@ public sealed class PeopleRepositoryUpdatePeopleTests : IDisposable ctx.SaveChanges(); } - var factory = new Mock<IDbContextFactory<JellyfinDbContext>>(); - factory.Setup(f => f.CreateDbContext()).Returns(CreateDbContext); - _repository = new PeopleRepository( - factory.Object, + CreateDbContextFactory(), itemTypeLookup, new Mock<IItemQueryHelpers>().Object); } - public void Dispose() - { - _connection.Dispose(); - } - [Fact] public void UpdatePeople_SamePersonAndTypeWithDifferentRoles_KeepsEveryCredit() { @@ -174,13 +151,4 @@ public sealed class PeopleRepositoryUpdatePeopleTests : IDisposable Role = role }; } - - private JellyfinDbContext CreateDbContext() - { - return new JellyfinDbContext( - _dbOptions, - NullLogger<JellyfinDbContext>.Instance, - new SqliteDatabaseProvider(null!, NullLogger<SqliteDatabaseProvider>.Instance), - new NoLockBehavior(NullLogger<NoLockBehavior>.Instance)); - } } diff --git a/tests/Jellyfin.Server.Implementations.Tests/Item/SqliteDbTestFixture.cs b/tests/Jellyfin.Server.Implementations.Tests/Item/SqliteDbTestFixture.cs new file mode 100644 index 0000000000..6be8244c1e --- /dev/null +++ b/tests/Jellyfin.Server.Implementations.Tests/Item/SqliteDbTestFixture.cs @@ -0,0 +1,85 @@ +using System; +using Emby.Server.Implementations.Data; +using Jellyfin.Database.Implementations; +using Jellyfin.Database.Implementations.Locking; +using Jellyfin.Database.Providers.Sqlite; +using Jellyfin.Server.Implementations.Item; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Model.Configuration; +using Microsoft.Data.Sqlite; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging.Abstractions; +using Moq; + +namespace Jellyfin.Server.Implementations.Tests.Item; + +/// <summary> +/// Base fixture for the item tests that run against the SQLite provider: one in-memory database per +/// test class, plus the wiring the repositories under test need. The connection owns the database, so +/// it stays open for the lifetime of the fixture. Derived classes seed in their own constructor. +/// </summary> +public abstract class SqliteDbTestFixture : IDisposable +{ + private readonly SqliteConnection _connection; + private readonly DbContextOptions<JellyfinDbContext> _dbOptions; + + protected SqliteDbTestFixture() + { + ApplicationPaths = new Mock<IApplicationPaths>().Object; + + _connection = new SqliteConnection("Data Source=:memory:"); + _connection.Open(); + + _dbOptions = new DbContextOptionsBuilder<JellyfinDbContext>() + .UseSqlite(_connection) + .Options; + + using var context = CreateDbContext(); + context.Database.EnsureCreated(); + } + + protected IApplicationPaths ApplicationPaths { get; } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected JellyfinDbContext CreateDbContext() => new( + _dbOptions, + NullLogger<JellyfinDbContext>.Instance, + new SqliteDatabaseProvider(ApplicationPaths, NullLogger<SqliteDatabaseProvider>.Instance), + new NoLockBehavior(NullLogger<NoLockBehavior>.Instance)); + + protected IDbContextFactory<JellyfinDbContext> CreateDbContextFactory() + { + var factory = new Mock<IDbContextFactory<JellyfinDbContext>>(); + factory.Setup(f => f.CreateDbContext()).Returns(CreateDbContext); + + return factory.Object; + } + + protected BaseItemRepository CreateBaseItemRepository(ItemTypeLookup itemTypeLookup) + { + var serverConfigurationManager = new Mock<IServerConfigurationManager>(); + serverConfigurationManager.Setup(c => c.Configuration).Returns(new ServerConfiguration()); + + return new BaseItemRepository( + CreateDbContextFactory(), + new Mock<IServerApplicationHost>().Object, + itemTypeLookup, + serverConfigurationManager.Object, + NullLogger<BaseItemRepository>.Instance); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _connection.Dispose(); + } + } +} |
