Scanner Fixes (#3619)

Co-authored-by: Fesaa <77553571+Fesaa@users.noreply.github.com>
This commit is contained in:
Joe Milazzo 2025-03-12 17:25:15 -05:00 committed by GitHub
parent b4061e3711
commit ab540c0ea6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 340 additions and 19 deletions

View file

@ -1,8 +1,11 @@
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.IO;
using System.IO.Abstractions;
using System.IO.Abstractions.TestingHelpers;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using API.Data;
using API.Data.Metadata;
@ -15,13 +18,16 @@ using API.Services;
using API.Services.Tasks.Scanner;
using API.Services.Tasks.Scanner.Parser;
using API.SignalR;
using API.Tests.Helpers;
using AutoMapper;
using Hangfire;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.Logging;
using NSubstitute;
using Xunit;
using Xunit.Abstractions;
namespace API.Tests.Services;
@ -97,11 +103,13 @@ public class MockReadingItemService : IReadingItemService
public class ParseScannedFilesTests : AbstractDbTest
{
private readonly ILogger<ParseScannedFiles> _logger = Substitute.For<ILogger<ParseScannedFiles>>();
private readonly ScannerHelper _scannerHelper;
public ParseScannedFilesTests()
public ParseScannedFilesTests(ITestOutputHelper testOutputHelper)
{
// Since ProcessFile relies on _readingItemService, we can implement our own versions of _readingItemService so we have control over how the calls work
GlobalConfiguration.Configuration.UseInMemoryStorage();
_scannerHelper = new ScannerHelper(_unitOfWork, testOutputHelper);
}
protected override async Task ResetDb()
@ -349,4 +357,98 @@ public class ParseScannedFilesTests : AbstractDbTest
#endregion
[Fact]
public async Task HasSeriesFolderNotChangedSinceLastScan_AllSeriesFoldersHaveChanges()
{
const string testcase = "Subfolders always scanning all series changes - Manga.json";
var infos = new Dictionary<string, ComicInfo>();
var library = await _scannerHelper.GenerateScannerData(testcase, infos);
var testDirectoryPath = library.Folders.First().Path;
_unitOfWork.LibraryRepository.Update(library);
await _unitOfWork.CommitAsync();
var fs = new FileSystem();
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fs);
var psf = new ParseScannedFiles(Substitute.For<ILogger<ParseScannedFiles>>(), ds,
new MockReadingItemService(ds, Substitute.For<IBookService>()), Substitute.For<IEventHub>());
var scanner = _scannerHelper.CreateServices(ds, fs);
await scanner.ScanLibrary(library.Id);
var postLib = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(library.Id, LibraryIncludes.Series);
Assert.NotNull(postLib);
Assert.Equal(4, postLib.Series.Count);
var spiceAndWolf = postLib.Series.First(x => x.Name == "Spice and Wolf");
Assert.Equal(2, spiceAndWolf.Volumes.Count);
var frieren = postLib.Series.First(x => x.Name == "Frieren - Beyond Journey's End");
Assert.Single(frieren.Volumes);
var executionerAndHerWayOfLife = postLib.Series.First(x => x.Name == "The Executioner and Her Way of Life");
Assert.Equal(2, executionerAndHerWayOfLife.Volumes.Count);
Thread.Sleep(1100); // Ensure at least one second has passed since library scan
// Add a new chapter to a volume of the series, and scan. Validate that only, and all directories of this
// series are marked as HasChanged
var executionerCopyDir = Path.Join(Path.Join(testDirectoryPath, "The Executioner and Her Way of Life"),
"The Executioner and Her Way of Life Vol. 1");
File.Copy(Path.Join(executionerCopyDir, "The Executioner and Her Way of Life Vol. 1 Ch. 0001.cbz"),
Path.Join(executionerCopyDir, "The Executioner and Her Way of Life Vol. 1 Ch. 0002.cbz"));
// 4 series, of which 2 have volumes as directories
var folderMap = await _unitOfWork.SeriesRepository.GetFolderPathMap(postLib.Id);
Assert.Equal(6, folderMap.Count);
var res = await psf.ScanFiles(testDirectoryPath, true, folderMap, postLib);
var changes = res.Where(sc => sc.HasChanged).ToList();
Assert.Equal(2, changes.Count);
// Only volumes of The Executioner and Her Way of Life should be marked as HasChanged (Spice and Wolf also has 2 volumes dirs)
Assert.Equal(2, changes.Count(sc => sc.Folder.Contains("The Executioner and Her Way of Life")));
}
[Fact]
public async Task HasSeriesFolderNotChangedSinceLastScan_PublisherLayout()
{
const string testcase = "Subfolder always scanning fix publisher layout - Comic.json";
var infos = new Dictionary<string, ComicInfo>();
var library = await _scannerHelper.GenerateScannerData(testcase, infos);
var testDirectoryPath = library.Folders.First().Path;
_unitOfWork.LibraryRepository.Update(library);
await _unitOfWork.CommitAsync();
var fs = new FileSystem();
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fs);
var psf = new ParseScannedFiles(Substitute.For<ILogger<ParseScannedFiles>>(), ds,
new MockReadingItemService(ds, Substitute.For<IBookService>()), Substitute.For<IEventHub>());
var scanner = _scannerHelper.CreateServices(ds, fs);
await scanner.ScanLibrary(library.Id);
var postLib = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(library.Id, LibraryIncludes.Series);
Assert.NotNull(postLib);
Assert.Equal(4, postLib.Series.Count);
var spiceAndWolf = postLib.Series.First(x => x.Name == "Spice and Wolf");
Assert.Equal(2, spiceAndWolf.Volumes.Count);
var frieren = postLib.Series.First(x => x.Name == "Frieren - Beyond Journey's End");
Assert.Equal(2, frieren.Volumes.Count);
Thread.Sleep(1100); // Ensure at least one second has passed since library scan
// Add a volume to a series, and scan. Ensure only this series is marked as HasChanged
var executionerCopyDir = Path.Join(Path.Join(testDirectoryPath, "YenPress"), "The Executioner and Her Way of Life");
File.Copy(Path.Join(executionerCopyDir, "The Executioner and Her Way of Life Vol. 1.cbz"),
Path.Join(executionerCopyDir, "The Executioner and Her Way of Life Vol. 2.cbz"));
var res = await psf.ScanFiles(testDirectoryPath, true,
await _unitOfWork.SeriesRepository.GetFolderPathMap(postLib.Id), postLib);
var changes = res.Count(sc => sc.HasChanged);
Assert.Equal(1, changes);
}
}