Files
TeleWave/backend/tests/TeleWave.Integration.Tests/TransactionIntegrationTests.cs
T

114 lines
4.0 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(
new MediaReadyInfo(
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>());
}
}