Files
ersatztv/ErsatzTV.Tests/Integration/PlayoutLifecycleIntegrationTests.cs
T
timothy b53b06c615
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 3m34s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 4m48s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
feat(api): add playout REST endpoints
fixes #37
2026-06-29 20:31:18 +02:00

131 lines
4.9 KiB
C#

using System.Threading.Channels;
using ErsatzTV.Application;
using ErsatzTV.Application.Playouts;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Scheduling;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Tests.Support;
using LanguageExt;
using MediatR;
using Microsoft.EntityFrameworkCore;
using NSubstitute;
using NUnit.Framework;
using Shouldly;
using Testably.Abstractions.Testing;
using Unit = LanguageExt.Unit;
using Channel = System.Threading.Channels.Channel;
namespace ErsatzTV.Tests.Integration;
[TestFixture]
public class PlayoutLifecycleIntegrationTests
{
private InMemoryTvContext _db = null!;
private Channel<IBackgroundServiceRequest> _worker = null!;
[SetUp]
public async Task SetUp()
{
_db = await InMemoryTvContext.CreateAsync();
_worker = Channel.CreateUnbounded<IBackgroundServiceRequest>();
}
[TearDown]
public async Task TearDown() => await _db.DisposeAsync();
[Test]
public async Task CreateClassic_Should_Link_Channel_And_Schedule_And_Enqueue_Build()
{
(int channelId, int scheduleId) = await SeedChannelAndSchedule();
var handler = new CreateClassicPlayoutHandler(_worker.Writer, _db.Factory);
Either<BaseError, CreatePlayoutResponse> result =
await handler.Handle(new CreateClassicPlayout(channelId, scheduleId), CancellationToken.None);
CreatePlayoutResponse response = result.Match(
Right: r => r,
Left: error => throw new AssertionException(error.Value));
await using TvContext context = _db.CreateContext();
Playout playout = await context.Playouts.SingleAsync();
playout.Id.ShouldBe(response.PlayoutId);
playout.ChannelId.ShouldBe(channelId);
playout.ProgramScheduleId.ShouldBe(scheduleId);
playout.ScheduleKind.ShouldBe(PlayoutScheduleKind.Classic);
IBackgroundServiceRequest backgroundRequest = await _worker.Reader.ReadAsync();
backgroundRequest.ShouldBeOfType<BuildPlayout>().PlayoutId.ShouldBe(playout.Id);
}
[Test]
public async Task Delete_Should_Remove_Playout_Without_Deleting_Channel_Or_Schedule()
{
(int channelId, int scheduleId) = await SeedChannelAndSchedule();
var createHandler = new CreateClassicPlayoutHandler(_worker.Writer, _db.Factory);
int playoutId = (await createHandler.Handle(new CreateClassicPlayout(channelId, scheduleId), CancellationToken.None))
.Match(Right: r => r.PlayoutId, Left: error => throw new AssertionException(error.Value));
var deleteHandler = new DeletePlayoutHandler(
_worker.Writer,
_db.Factory,
new MockFileSystem(),
Substitute.For<IMediator>());
Either<BaseError, Unit> result = await deleteHandler.Handle(new DeletePlayout(playoutId), CancellationToken.None);
result.IsRight.ShouldBeTrue();
await using TvContext context = _db.CreateContext();
(await context.Playouts.CountAsync()).ShouldBe(0);
(await context.Channels.CountAsync(c => c.Id == channelId)).ShouldBe(1);
(await context.ProgramSchedules.CountAsync(ps => ps.Id == scheduleId)).ShouldBe(1);
}
private async Task<(int ChannelId, int ScheduleId)> SeedChannelAndSchedule()
{
await using TvContext context = _db.CreateContext();
var channel = new ErsatzTV.Core.Domain.Channel(Guid.NewGuid())
{
Number = "101",
SortNumber = 101,
Name = "Lifecycle",
Group = string.Empty,
Categories = string.Empty,
StreamingMode = StreamingMode.HttpLiveStreamingSegmenter,
Playouts = [],
Artwork = [],
StreamSelector = string.Empty,
PreferredAudioLanguageCode = string.Empty,
PreferredAudioTitle = string.Empty,
PreferredSubtitleLanguageCode = string.Empty,
MusicVideoCreditsTemplate = string.Empty,
PlayoutSource = ChannelPlayoutSource.Generated,
PlayoutMode = ChannelPlayoutMode.Continuous,
IsEnabled = true,
ShowInEpg = true
};
var schedule = new ProgramSchedule
{
Name = "Lifecycle",
Items =
[
new ProgramScheduleItemOne
{
Index = 0,
CollectionType = CollectionType.SearchQuery,
SearchQuery = "news",
PlaybackOrder = PlaybackOrder.Shuffle,
GuideMode = GuideMode.Normal,
Watermarks = [],
GraphicsElements = []
}
],
Playouts = [],
ProgramScheduleAlternates = []
};
context.Channels.Add(channel);
context.ProgramSchedules.Add(schedule);
await context.SaveChangesAsync();
return (channel.Id, schedule.Id);
}
}