134 lines
5.4 KiB
C#
134 lines
5.4 KiB
C#
using NSubstitute;
|
|
using TeleWave.Application.Common.Interfaces;
|
|
using TeleWave.Application.Media.ManualInbox;
|
|
using TeleWave.Domain.Library;
|
|
using TeleWave.Domain.Media;
|
|
using TeleWave.Infrastructure.Persistence;
|
|
using Xunit;
|
|
|
|
namespace TeleWave.Integration.Tests;
|
|
|
|
/// <summary>
|
|
/// Ручной разбор <c>manual/</c>: выбранные файлы уходят из каталога в шоу. Проверяется против
|
|
/// настоящей БД, потому что вся суть операции — в связке «ассет + серия шоу + файл на диске».
|
|
/// </summary>
|
|
[Collection("postgres")]
|
|
public sealed class ManualInboxIntegrationTests(PostgresFixture fixture)
|
|
{
|
|
[SkippableFact]
|
|
public async Task Import_AddsEpisodesToShow_AndConsumesFiles()
|
|
{
|
|
Skip.IfNot(fixture.Available, "Docker недоступен");
|
|
|
|
await using var seedDb = fixture.CreateContext();
|
|
var showId = await SeedShowAsync(seedDb);
|
|
var tag = Guid.NewGuid().ToString("N")[..8];
|
|
var first = $"{tag}-s01e01.mkv";
|
|
var second = $"{tag}-s01e02.mkv";
|
|
|
|
var storage = Substitute.For<IMediaStorage>();
|
|
storage
|
|
.ListManualInbox(Arg.Any<int>())
|
|
.Returns(
|
|
[
|
|
new IMediaStorage.ManualInboxFile($"Сериал/{first}", first, 1000),
|
|
new IMediaStorage.ManualInboxFile($"Сериал/{second}", second, 1000),
|
|
]
|
|
);
|
|
|
|
await using var db = fixture.CreateContext();
|
|
var result = await new ImportManualInboxCommandHandler(
|
|
db,
|
|
storage,
|
|
Substitute.For<IMediaProcessingQueue>()
|
|
).Handle(
|
|
new ImportManualInboxCommand([$"Сериал/{first}", $"Сериал/{second}"], showId),
|
|
default
|
|
);
|
|
|
|
Assert.True(result.IsSuccess);
|
|
Assert.Equal(2, result.Value.Imported);
|
|
Assert.Empty(result.Value.Failed);
|
|
await db.SaveChangesAsync();
|
|
|
|
// Файлы должны быть перенесены из manual/ — ровно как из обычного inbox.
|
|
await storage
|
|
.Received(2)
|
|
.PromoteToOriginalAsync(
|
|
MediaSource.ManualInbox,
|
|
Arg.Any<string>(),
|
|
Arg.Any<Guid>(),
|
|
".mkv",
|
|
Arg.Any<CancellationToken>()
|
|
);
|
|
|
|
await using var verify = fixture.CreateContext();
|
|
var episodes = verify
|
|
.Shows.Where(s => s.Id == showId)
|
|
.SelectMany(s => s.Episodes)
|
|
.OrderBy(e => e.Position)
|
|
.ToList();
|
|
|
|
Assert.Equal(2, episodes.Count);
|
|
// Номера сезона и серии разбираются из имени файла, как при обычном добавлении.
|
|
Assert.Equal(1, episodes[0].Season);
|
|
Assert.Equal(1, episodes[0].Episode);
|
|
Assert.Equal(2, episodes[1].Episode);
|
|
|
|
// Считаем ассеты своего шоу: база в интеграционных тестах общая, и соседний тест тоже
|
|
// заводит записи из ручного inbox.
|
|
var assetIds = episodes.Select(e => e.MediaAssetId).ToList();
|
|
var assets = verify.MediaAssets.Where(a => assetIds.Contains(a.Id)).ToList();
|
|
Assert.Equal(2, assets.Count);
|
|
Assert.All(assets, a => Assert.Equal(MediaSource.ManualInbox, a.Source));
|
|
Assert.All(assets, a => Assert.Equal(MediaAssetStatus.Pending, a.Status));
|
|
}
|
|
|
|
[SkippableFact]
|
|
public async Task Import_SkipsUnsupportedAndMissing_WithoutFailingTheBatch()
|
|
{
|
|
Skip.IfNot(fixture.Available, "Docker недоступен");
|
|
|
|
await using var seedDb = fixture.CreateContext();
|
|
var showId = await SeedShowAsync(seedDb);
|
|
|
|
var tag = Guid.NewGuid().ToString("N")[..8];
|
|
var good = $"{tag}-ok.mkv";
|
|
|
|
var storage = Substitute.For<IMediaStorage>();
|
|
storage
|
|
.ListManualInbox(Arg.Any<int>())
|
|
.Returns(
|
|
[
|
|
new IMediaStorage.ManualInboxFile(good, good, 1000),
|
|
new IMediaStorage.ManualInboxFile("readme.txt", "readme.txt", 10),
|
|
]
|
|
);
|
|
|
|
await using var db = fixture.CreateContext();
|
|
var result = await new ImportManualInboxCommandHandler(
|
|
db,
|
|
storage,
|
|
Substitute.For<IMediaProcessingQueue>()
|
|
).Handle(
|
|
new ImportManualInboxCommand([good, "readme.txt", "ушёл.mkv"], showId),
|
|
default
|
|
);
|
|
|
|
// Один взяли, два отклонили — и каждый со своей причиной, а не одной ошибкой на пакет.
|
|
Assert.True(result.IsSuccess);
|
|
Assert.Equal(1, result.Value.Imported);
|
|
Assert.Equal(2, result.Value.Failed.Count);
|
|
Assert.Contains(result.Value.Failed, f => f.RelativePath == "readme.txt");
|
|
Assert.Contains(result.Value.Failed, f => f.RelativePath == "ушёл.mkv");
|
|
}
|
|
|
|
private static async Task<Guid> SeedShowAsync(AppDbContext db)
|
|
{
|
|
var show = Show.Create($"Сериал {Guid.NewGuid():N}"[..20], ShowKind.Series);
|
|
db.Shows.Add(show);
|
|
await db.SaveChangesAsync();
|
|
return show.Id;
|
|
}
|
|
}
|