using ErsatzTV.Core.Domain; using ErsatzTV.Infrastructure.Data; using ErsatzTV.Infrastructure.Data.Repositories; using ErsatzTV.Tests.Support; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging.Abstractions; using NUnit.Framework; using Shouldly; namespace ErsatzTV.Tests.Integration; // ersatztv#460: the disable-sync (remove-and-recreate) flows used to stamp the 0001-01-01 MinValue // sentinel into Library.LastScan. #409 fixed the READ side (the API coerces the sentinel to null and a // migration cleaned historical rows), so the wire contract was already correct — these tests pin the // WRITE side for every provider, so no NEW sentinel rows are created. They do not (and cannot) speak to // rows already written before this change: those keep the sentinel at rest and are covered only by the // read-boundary coercion, since this ships no second cleanup migration. [TestFixture] public class MediaSourceRepositoryDisableSyncTests { private InMemoryTvContext _db = null!; private MediaSourceRepository _repository = null!; [SetUp] public async Task SetUp() { _db = await InMemoryTvContext.CreateAsync(); _repository = new MediaSourceRepository(_db.Factory, NullLogger.Instance); } [TearDown] public async Task TearDown() => await _db.DisposeAsync(); [Test] public async Task DisablePlexLibrarySync_Should_Null_LastScan_Not_Write_MinValue() { int libraryId = await Seed(new PlexLibrary { Name = "Movies", MediaKind = LibraryMediaKind.Movies, MediaSourceId = 1, Key = "key1", ShouldSyncItems = true, LastScan = new DateTime(2026, 7, 1, 12, 0, 0, DateTimeKind.Utc), Paths = [new LibraryPath { Path = "/data/movies" }] }); await _repository.DisablePlexLibrarySync([libraryId]); await using TvContext context = _db.CreateContext(); PlexLibrary library = await context.PlexLibraries.SingleAsync(l => l.Name == "Movies"); library.LastScan.ShouldBeNull(); library.ShouldSyncItems.ShouldBeFalse(); } [Test] public async Task DisableJellyfinLibrarySync_Should_Null_LastScan_Not_Write_MinValue() { int libraryId = await Seed(new JellyfinLibrary { Name = "Concerts", MediaKind = LibraryMediaKind.MusicVideos, MediaSourceId = 1, ItemId = "item1", ShouldSyncItems = true, LastScan = new DateTime(2026, 7, 1, 12, 0, 0, DateTimeKind.Utc), Paths = [new LibraryPath { Path = "/data/music" }], PathInfos = [] }); await _repository.DisableJellyfinLibrarySync([libraryId]); await using TvContext context = _db.CreateContext(); JellyfinLibrary library = await context.JellyfinLibraries.SingleAsync(l => l.Name == "Concerts"); library.LastScan.ShouldBeNull(); library.ShouldSyncItems.ShouldBeFalse(); } [Test] public async Task DisableEmbyLibrarySync_Should_Null_LastScan_Not_Write_MinValue() { int libraryId = await Seed(new EmbyLibrary { Name = "Shows", MediaKind = LibraryMediaKind.Shows, MediaSourceId = 1, ItemId = "item1", ShouldSyncItems = true, LastScan = new DateTime(2026, 7, 1, 12, 0, 0, DateTimeKind.Utc), Paths = [new LibraryPath { Path = "/data/shows" }], PathInfos = [] }); await _repository.DisableEmbyLibrarySync([libraryId]); await using TvContext context = _db.CreateContext(); EmbyLibrary library = await context.EmbyLibraries.SingleAsync(l => l.Name == "Shows"); library.LastScan.ShouldBeNull(); library.ShouldSyncItems.ShouldBeFalse(); } private async Task Seed(Library library) { await using TvContext context = _db.CreateContext(); await context.AddAsync(library); await context.SaveChangesAsync(); return library.Id; } }