using NSubstitute; using TeleWave.Application.Common.Interfaces; using TeleWave.Application.Media.Stats; using TeleWave.Application.Tests.Support; using TeleWave.Domain.Media; using Xunit; namespace TeleWave.Application.Tests.Media; public class MediaStatsTests { private static MediaAsset Pending(string name) => MediaAsset.Register(name, ".mkv", MediaSource.Upload); private static MediaAsset Processing(string name) { var a = Pending(name); a.MarkProcessing(); return a; } private static MediaAsset Ready(string name) { var a = Pending(name); a.MarkProcessing(); a.MarkReady( new MediaReadyInfo( TimeSpan.FromMinutes(20), 2, 600, 1920, 1080, "h264", "aac", "assets/x" ) ); return a; } [Fact] public async Task Stats_CountsQueuedAndProcessing_AndAveragesReady_ExcludingGenerated() { var fixture = new TestDb(); await using (var seed = fixture.New()) { seed.MediaAssets.AddRange( Pending("a.mkv"), Pending("b.mkv"), Processing("c.mkv"), Ready("d.mkv"), MediaAsset.RegisterGenerated("Заставка") // Generated — не входит в статистику ); await seed.SaveChangesAsync(CancellationToken.None); } await using var db = fixture.New(); var stats = await new GetMediaStatsQueryHandler(db, Limits(1)).Handle( new GetMediaStatsQuery(), CancellationToken.None ); Assert.Equal(2, stats.Queued); // два Pending (Generated исключён) Assert.Equal(1, stats.Processing); Assert.NotNull(stats.AverageProcessingSeconds); Assert.True(stats.AverageProcessingSeconds >= 0); } [Fact] public async Task Estimate_ScalesWithQueueAndParallelism() { var fixture = new TestDb(); await using (var seed = fixture.New()) { // Одна завершённая задаёт среднее, четыре ждут своей очереди. seed.MediaAssets.AddRange( Ready("done.mkv"), Pending("a.mkv"), Pending("b.mkv"), Pending("c.mkv"), Pending("d.mkv") ); await seed.SaveChangesAsync(CancellationToken.None); } await using var db = fixture.New(); var single = await new GetMediaStatsQueryHandler(db, Limits(1)).Handle( new GetMediaStatsQuery(), CancellationToken.None ); var parallel = await new GetMediaStatsQueryHandler(db, Limits(2)).Handle( new GetMediaStatsQuery(), CancellationToken.None ); var average = single.AverageProcessingSeconds!.Value; Assert.Equal(4 * average, single.EstimatedRemainingSeconds!.Value, 3); // Два транскода одновременно — вдвое меньше ждать. Assert.Equal( single.EstimatedRemainingSeconds!.Value / 2, parallel.EstimatedRemainingSeconds!.Value, 3 ); } [Fact] public async Task Estimate_IsAbsent_WhenQueueIsEmpty() { var fixture = new TestDb(); await using (var seed = fixture.New()) { seed.MediaAssets.Add(Ready("done.mkv")); await seed.SaveChangesAsync(CancellationToken.None); } await using var db = fixture.New(); var stats = await new GetMediaStatsQueryHandler(db, Limits(1)).Handle( new GetMediaStatsQuery(), CancellationToken.None ); // Ждать нечего — оценки нет вовсе, а не «0 секунд». Assert.Null(stats.EstimatedRemainingSeconds); } private static IMediaProcessingLimits Limits(int parallel) { var limits = Substitute.For(); limits.MaxParallelTranscodes.Returns(parallel); return limits; } }