101 lines
3.8 KiB
C#
101 lines
3.8 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using NSubstitute;
|
|
using TeleWave.Application.Common.Interfaces;
|
|
using TeleWave.Application.Maintenance.DeleteShowMedia;
|
|
using TeleWave.Application.Media.Register;
|
|
using TeleWave.Domain.Broadcast;
|
|
using TeleWave.Domain.Library;
|
|
using TeleWave.Domain.Media;
|
|
using Xunit;
|
|
|
|
namespace TeleWave.Integration.Tests;
|
|
|
|
[Collection("postgres")]
|
|
public sealed class TransactionIntegrationTests(PostgresFixture fixture)
|
|
{
|
|
[SkippableFact]
|
|
public async Task RegisterMediaAsset_RollsBack_WhenFilePromoteFails()
|
|
{
|
|
Skip.IfNot(fixture.Available, "Docker недоступен");
|
|
var fileName = $"clip-{Guid.NewGuid():N}.mkv";
|
|
var storage = Substitute.For<IMediaStorage>();
|
|
storage
|
|
.PromoteToOriginalAsync(
|
|
Arg.Any<MediaSource>(),
|
|
Arg.Any<string>(),
|
|
Arg.Any<Guid>(),
|
|
Arg.Any<string>(),
|
|
Arg.Any<CancellationToken>()
|
|
)
|
|
.Returns(Task.FromException(new IOException("disk full")));
|
|
|
|
await using var db = fixture.CreateContext();
|
|
var handler = new RegisterMediaAssetCommandHandler(db, storage);
|
|
|
|
await Assert.ThrowsAsync<IOException>(() =>
|
|
handler.Handle(
|
|
new RegisterMediaAssetCommand(fileName, MediaSource.Upload, fileName),
|
|
CancellationToken.None
|
|
)
|
|
);
|
|
|
|
// Перенос файла упал — регистрация должна откатиться, чтобы не осталось orphan-строки.
|
|
await using var verify = fixture.CreateContext();
|
|
var exists = await verify.MediaAssets.AnyAsync(a => a.OriginalFileName == fileName);
|
|
Assert.False(exists);
|
|
}
|
|
|
|
[SkippableFact]
|
|
public async Task DeleteShowMedia_AtomicallyRemovesEntriesAssetsAndEpisodes()
|
|
{
|
|
Skip.IfNot(fixture.Available, "Docker недоступен");
|
|
var channel = Channel.Create("c", $"c-{Guid.NewGuid():N}", DateTimeOffset.UnixEpoch);
|
|
var show = Show.Create("Show", ShowKind.Series);
|
|
var asset = MediaAsset.Register("ep.mkv", ".mkv", MediaSource.Upload);
|
|
asset.MarkReady(TimeSpan.FromMinutes(20), 2, 600, 1920, 1080, "h264", "aac", "assets/x");
|
|
show.AddEpisode(asset.Id);
|
|
var entry = ScheduleEntry.Program(
|
|
channel.Id,
|
|
asset.Id,
|
|
DateTimeOffset.UnixEpoch,
|
|
DateTimeOffset.UnixEpoch.AddMinutes(20),
|
|
show.Id,
|
|
0
|
|
);
|
|
|
|
await using (var seed = fixture.CreateContext())
|
|
{
|
|
seed.Channels.Add(channel);
|
|
seed.Shows.Add(show);
|
|
seed.MediaAssets.Add(asset);
|
|
seed.ScheduleEntries.Add(entry);
|
|
await seed.SaveChangesAsync(CancellationToken.None);
|
|
}
|
|
|
|
var storage = Substitute.For<IMediaStorage>();
|
|
storage
|
|
.DeleteAssetArtifactsAsync(Arg.Any<Guid>(), Arg.Any<string>(), Arg.Any<CancellationToken>())
|
|
.Returns(Task.CompletedTask);
|
|
|
|
await using (var db = fixture.CreateContext())
|
|
{
|
|
var result = await new DeleteShowMediaCommandHandler(db, storage).Handle(
|
|
new DeleteShowMediaCommand(show.Id),
|
|
CancellationToken.None
|
|
);
|
|
Assert.True(result.IsSuccess);
|
|
}
|
|
|
|
await using var verify = fixture.CreateContext();
|
|
Assert.False(await verify.MediaAssets.AnyAsync(a => a.Id == asset.Id));
|
|
Assert.False(await verify.ScheduleEntries.AnyAsync(e => e.MediaAssetId == asset.Id));
|
|
var reloaded = await verify
|
|
.Shows.Include(s => s.Episodes)
|
|
.FirstAsync(s => s.Id == show.Id);
|
|
Assert.Empty(reloaded.Episodes);
|
|
await storage
|
|
.Received()
|
|
.DeleteAssetArtifactsAsync(asset.Id, ".mkv", Arg.Any<CancellationToken>());
|
|
}
|
|
}
|