218 lines
7.2 KiB
C#
218 lines
7.2 KiB
C#
using System.Threading.Channels;
|
|
using ErsatzTV.Application;
|
|
using ErsatzTV.Application.ProgramSchedules;
|
|
using ErsatzTV.Core;
|
|
using ErsatzTV.Core.Domain;
|
|
using ErsatzTV.Core.Errors;
|
|
using ErsatzTV.Core.Scheduling;
|
|
using ErsatzTV.Infrastructure.Data;
|
|
using ErsatzTV.Tests.Support;
|
|
using LanguageExt;
|
|
using NUnit.Framework;
|
|
using Shouldly;
|
|
using Unit = LanguageExt.Unit;
|
|
|
|
namespace ErsatzTV.Tests.Application.ProgramSchedules;
|
|
|
|
[TestFixture]
|
|
public class ProgramScheduleHandlerTests
|
|
{
|
|
private InMemoryTvContext _db = null!;
|
|
private ChannelWriter<IBackgroundServiceRequest> _worker = null!;
|
|
|
|
[SetUp]
|
|
public async Task SetUp()
|
|
{
|
|
_db = await InMemoryTvContext.CreateAsync();
|
|
_worker = System.Threading.Channels.Channel.CreateUnbounded<IBackgroundServiceRequest>().Writer;
|
|
}
|
|
|
|
[TearDown]
|
|
public async Task TearDown() => await _db.DisposeAsync();
|
|
|
|
[Test]
|
|
public async Task Update_Should_Return_NotFoundError_When_Schedule_Missing()
|
|
{
|
|
var handler = new UpdateProgramScheduleHandler(_db.Factory, _worker);
|
|
|
|
Either<BaseError, UpdateProgramScheduleResult> result =
|
|
await handler.Handle(MakeUpdate(999, "Missing"), CancellationToken.None);
|
|
|
|
LeftOf(result).ShouldBeOfType<NotFoundError>();
|
|
}
|
|
|
|
[Test]
|
|
public async Task Delete_Should_Return_NotFoundError_When_Schedule_Missing()
|
|
{
|
|
var handler = new DeleteProgramScheduleHandler(_db.Factory);
|
|
|
|
Either<BaseError, Unit> result =
|
|
await handler.Handle(new DeleteProgramSchedule(999), CancellationToken.None);
|
|
|
|
LeftOf(result).ShouldBeOfType<NotFoundError>();
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddItem_Should_Return_NotFoundError_When_Schedule_Missing()
|
|
{
|
|
var handler = new AddProgramScheduleItemHandler(_db.Factory, _worker);
|
|
|
|
Either<BaseError, ProgramScheduleItemViewModel> result =
|
|
await handler.Handle(MakeAdd(999, CollectionType.SearchQuery), CancellationToken.None);
|
|
|
|
LeftOf(result).ShouldBeOfType<NotFoundError>();
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddItem_Should_Return_ValidationError_When_Collection_Type_Is_Invalid()
|
|
{
|
|
int scheduleId = await SeedSchedule();
|
|
var handler = new AddProgramScheduleItemHandler(_db.Factory, _worker);
|
|
|
|
Either<BaseError, ProgramScheduleItemViewModel> result =
|
|
await handler.Handle(MakeAdd(scheduleId, CollectionType.Collection), CancellationToken.None);
|
|
|
|
BaseError error = LeftOf(result);
|
|
error.ShouldNotBeOfType<NotFoundError>();
|
|
error.Value.ShouldContain("[Collection] is required");
|
|
}
|
|
|
|
[Test]
|
|
public async Task ReplaceItems_Should_Return_NotFoundError_When_Schedule_Missing()
|
|
{
|
|
var handler = new ReplaceProgramScheduleItemsHandler(_db.Factory, _worker);
|
|
|
|
Either<BaseError, IEnumerable<ProgramScheduleItemViewModel>> result =
|
|
await handler.Handle(
|
|
new ReplaceProgramScheduleItems(999, [MakeReplace(0)]),
|
|
CancellationToken.None);
|
|
|
|
LeftOf(result).ShouldBeOfType<NotFoundError>();
|
|
}
|
|
|
|
[Test]
|
|
public async Task DeleteItem_Should_Return_NotFoundError_When_Item_Missing()
|
|
{
|
|
int scheduleId = await SeedSchedule();
|
|
var handler = new DeleteProgramScheduleItemHandler(_db.Factory, _worker);
|
|
|
|
Either<BaseError, Unit> result =
|
|
await handler.Handle(new DeleteProgramScheduleItem(scheduleId, 999), CancellationToken.None);
|
|
|
|
LeftOf(result).ShouldBeOfType<NotFoundError>();
|
|
}
|
|
|
|
private async Task<int> SeedSchedule()
|
|
{
|
|
await using TvContext context = _db.CreateContext();
|
|
var schedule = new ProgramSchedule
|
|
{
|
|
Name = "Handlers",
|
|
Items = [],
|
|
Playouts = [],
|
|
ProgramScheduleAlternates = []
|
|
};
|
|
context.ProgramSchedules.Add(schedule);
|
|
await context.SaveChangesAsync();
|
|
return schedule.Id;
|
|
}
|
|
|
|
private static UpdateProgramSchedule MakeUpdate(int scheduleId, string name) =>
|
|
new(
|
|
scheduleId,
|
|
name,
|
|
KeepMultiPartEpisodesTogether: true,
|
|
TreatCollectionsAsShows: true,
|
|
ShuffleScheduleItems: false,
|
|
RandomStartPoint: false,
|
|
FixedStartTimeBehavior.Flexible);
|
|
|
|
private static AddProgramScheduleItem MakeAdd(int scheduleId, CollectionType collectionType) =>
|
|
new(
|
|
scheduleId,
|
|
StartType.Dynamic,
|
|
StartTime: null,
|
|
FixedStartTimeBehavior: null,
|
|
PlayoutMode.One,
|
|
collectionType,
|
|
CollectionId: null,
|
|
MultiCollectionId: null,
|
|
SmartCollectionId: null,
|
|
RerunCollectionId: null,
|
|
MediaItemId: null,
|
|
PlaylistId: null,
|
|
SearchTitle: "News",
|
|
SearchQuery: "news",
|
|
PlaybackOrder.Shuffle,
|
|
MarathonGroupBy.None,
|
|
MarathonShuffleGroups: false,
|
|
MarathonShuffleItems: false,
|
|
MarathonBatchSize: null,
|
|
FillWithGroupMode.None,
|
|
MultipleMode.Count,
|
|
MultipleCount: "1",
|
|
PlayoutDuration: null,
|
|
TailMode.None,
|
|
DiscardToFillAttempts: null,
|
|
CustomTitle: null,
|
|
GuideMode.Normal,
|
|
PreRollFillerId: null,
|
|
MidRollFillerId: null,
|
|
PostRollFillerId: null,
|
|
TailFillerId: null,
|
|
FallbackFillerId: null,
|
|
WatermarkIds: [],
|
|
GraphicsElementIds: [],
|
|
PreferredAudioLanguageCode: null,
|
|
PreferredAudioTitle: null,
|
|
PreferredSubtitleLanguageCode: null,
|
|
SubtitleMode: null);
|
|
|
|
private static ReplaceProgramScheduleItem MakeReplace(int index)
|
|
{
|
|
AddProgramScheduleItem add = MakeAdd(1, CollectionType.SearchQuery);
|
|
return new ReplaceProgramScheduleItem(
|
|
index,
|
|
add.StartType,
|
|
add.StartTime,
|
|
add.FixedStartTimeBehavior,
|
|
add.PlayoutMode,
|
|
add.CollectionType,
|
|
add.CollectionId,
|
|
add.MultiCollectionId,
|
|
add.SmartCollectionId,
|
|
add.RerunCollectionId,
|
|
add.MediaItemId,
|
|
add.PlaylistId,
|
|
add.SearchTitle,
|
|
add.SearchQuery,
|
|
add.PlaybackOrder,
|
|
add.MarathonGroupBy,
|
|
add.MarathonShuffleGroups,
|
|
add.MarathonShuffleItems,
|
|
add.MarathonBatchSize,
|
|
add.FillWithGroupMode,
|
|
add.MultipleMode,
|
|
add.MultipleCount,
|
|
add.PlayoutDuration,
|
|
add.TailMode,
|
|
add.DiscardToFillAttempts,
|
|
add.CustomTitle,
|
|
add.GuideMode,
|
|
add.PreRollFillerId,
|
|
add.MidRollFillerId,
|
|
add.PostRollFillerId,
|
|
add.TailFillerId,
|
|
add.FallbackFillerId,
|
|
add.WatermarkIds,
|
|
add.GraphicsElementIds,
|
|
add.PreferredAudioLanguageCode,
|
|
add.PreferredAudioTitle,
|
|
add.PreferredSubtitleLanguageCode,
|
|
add.SubtitleMode);
|
|
}
|
|
|
|
private static BaseError LeftOf<TR>(Either<BaseError, TR> either) =>
|
|
either.Match(Left: e => e, Right: _ => throw new AssertionException("Expected a Left result"));
|
|
}
|