feat(api): add route names and handler tests for picker list endpoints (#105)
The WIP GET /api/filler-presets, /api/watermarks, and /api/graphics-elements endpoints omitted the Name= route attribute used by the other API GET actions (e.g. FFmpegProfileController). Add Name = "GetFillerPresets" / "GetWatermarks" / "GetGraphicsElements" for consistency. Also add handler tests (FillerPresetHandlerTests, WatermarkHandlerTests, GraphicsElementHandlerTests) covering the GetAll*ForApi handlers using the InMemoryTvContext harness: multi-row projection to (Id, Name) DTOs, the empty-DB case, and the graphics-element ordering rule (named elements sort before elements whose projected Name equals FileName).
This commit is contained in:
@@ -0,0 +1,63 @@
|
|||||||
|
using ErsatzTV.Application.Filler;
|
||||||
|
using ErsatzTV.Core.Api.Filler;
|
||||||
|
using ErsatzTV.Core.Domain;
|
||||||
|
using ErsatzTV.Core.Domain.Filler;
|
||||||
|
using ErsatzTV.Infrastructure.Data;
|
||||||
|
using ErsatzTV.Tests.Support;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Shouldly;
|
||||||
|
|
||||||
|
namespace ErsatzTV.Tests.Application.Filler;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public class FillerPresetHandlerTests
|
||||||
|
{
|
||||||
|
private InMemoryTvContext _db = null!;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public async Task SetUp() => _db = await InMemoryTvContext.CreateAsync();
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public async Task TearDown() => await _db.DisposeAsync();
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task GetAllFillerPresetsForApi_Should_Return_All_Presets()
|
||||||
|
{
|
||||||
|
await SeedPreset(1, "Intro");
|
||||||
|
await SeedPreset(2, "Outro");
|
||||||
|
|
||||||
|
var handler = new GetAllFillerPresetsForApiHandler(_db.Factory);
|
||||||
|
|
||||||
|
List<FillerPresetResponseModel> result =
|
||||||
|
await handler.Handle(new GetAllFillerPresetsForApi(), CancellationToken.None);
|
||||||
|
|
||||||
|
result.Count.ShouldBe(2);
|
||||||
|
result.ShouldContain(new FillerPresetResponseModel(1, "Intro"));
|
||||||
|
result.ShouldContain(new FillerPresetResponseModel(2, "Outro"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task GetAllFillerPresetsForApi_Should_Return_Empty_List_When_None_Exist()
|
||||||
|
{
|
||||||
|
var handler = new GetAllFillerPresetsForApiHandler(_db.Factory);
|
||||||
|
|
||||||
|
List<FillerPresetResponseModel> result =
|
||||||
|
await handler.Handle(new GetAllFillerPresetsForApi(), CancellationToken.None);
|
||||||
|
|
||||||
|
result.ShouldBeEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SeedPreset(int id, string name)
|
||||||
|
{
|
||||||
|
await using TvContext context = _db.CreateContext();
|
||||||
|
context.FillerPresets.Add(new FillerPreset
|
||||||
|
{
|
||||||
|
Id = id,
|
||||||
|
Name = name,
|
||||||
|
FillerKind = FillerKind.PreRoll,
|
||||||
|
FillerMode = FillerMode.Duration,
|
||||||
|
CollectionType = CollectionType.Collection
|
||||||
|
});
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
using ErsatzTV.Application.Graphics;
|
||||||
|
using ErsatzTV.Core.Api.Graphics;
|
||||||
|
using ErsatzTV.Core.Domain;
|
||||||
|
using ErsatzTV.Infrastructure.Data;
|
||||||
|
using ErsatzTV.Tests.Support;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Shouldly;
|
||||||
|
|
||||||
|
namespace ErsatzTV.Tests.Application.Graphics;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public class GraphicsElementHandlerTests
|
||||||
|
{
|
||||||
|
private InMemoryTvContext _db = null!;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public async Task SetUp() => _db = await InMemoryTvContext.CreateAsync();
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public async Task TearDown() => await _db.DisposeAsync();
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task GetAllGraphicsElementsForApi_Should_Return_All_Elements()
|
||||||
|
{
|
||||||
|
await SeedElement(1, "watermark.png", GraphicsElementKind.Image, "Custom Watermark");
|
||||||
|
await SeedElement(2, "clock.png", GraphicsElementKind.Image, string.Empty);
|
||||||
|
|
||||||
|
var handler = new GetAllGraphicsElementsForApiHandler(_db.Factory);
|
||||||
|
|
||||||
|
List<GraphicsElementResponseModel> result =
|
||||||
|
await handler.Handle(new GetAllGraphicsElementsForApi(), CancellationToken.None);
|
||||||
|
|
||||||
|
result.Count.ShouldBe(2);
|
||||||
|
result.Select(e => e.Id).ShouldBe([1, 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task GetAllGraphicsElementsForApi_Should_Order_Named_Elements_Before_Unnamed()
|
||||||
|
{
|
||||||
|
// unnamed element's projected Name equals its FileName -> should sort after named elements
|
||||||
|
await SeedElement(1, "aaa.png", GraphicsElementKind.Image, string.Empty);
|
||||||
|
await SeedElement(2, "zzz.png", GraphicsElementKind.Image, "A Custom Name");
|
||||||
|
|
||||||
|
var handler = new GetAllGraphicsElementsForApiHandler(_db.Factory);
|
||||||
|
|
||||||
|
List<GraphicsElementResponseModel> result =
|
||||||
|
await handler.Handle(new GetAllGraphicsElementsForApi(), CancellationToken.None);
|
||||||
|
|
||||||
|
result.Count.ShouldBe(2);
|
||||||
|
result[0].Id.ShouldBe(2);
|
||||||
|
result[1].Id.ShouldBe(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task GetAllGraphicsElementsForApi_Should_Return_Empty_List_When_None_Exist()
|
||||||
|
{
|
||||||
|
var handler = new GetAllGraphicsElementsForApiHandler(_db.Factory);
|
||||||
|
|
||||||
|
List<GraphicsElementResponseModel> result =
|
||||||
|
await handler.Handle(new GetAllGraphicsElementsForApi(), CancellationToken.None);
|
||||||
|
|
||||||
|
result.ShouldBeEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SeedElement(int id, string path, GraphicsElementKind kind, string name)
|
||||||
|
{
|
||||||
|
await using TvContext context = _db.CreateContext();
|
||||||
|
context.GraphicsElements.Add(new GraphicsElement
|
||||||
|
{
|
||||||
|
Id = id,
|
||||||
|
Path = path,
|
||||||
|
Name = name,
|
||||||
|
Kind = kind
|
||||||
|
});
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
using ErsatzTV.Application.Watermarks;
|
||||||
|
using ErsatzTV.Core.Api.Watermarks;
|
||||||
|
using ErsatzTV.Core.Domain;
|
||||||
|
using ErsatzTV.FFmpeg.State;
|
||||||
|
using ErsatzTV.Infrastructure.Data;
|
||||||
|
using ErsatzTV.Tests.Support;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Shouldly;
|
||||||
|
|
||||||
|
namespace ErsatzTV.Tests.Application.Watermarks;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public class WatermarkHandlerTests
|
||||||
|
{
|
||||||
|
private InMemoryTvContext _db = null!;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public async Task SetUp() => _db = await InMemoryTvContext.CreateAsync();
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public async Task TearDown() => await _db.DisposeAsync();
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task GetAllWatermarksForApi_Should_Return_All_Watermarks()
|
||||||
|
{
|
||||||
|
await SeedWatermark(1, "Bug");
|
||||||
|
await SeedWatermark(2, "Logo");
|
||||||
|
|
||||||
|
var handler = new GetAllWatermarksForApiHandler(_db.Factory);
|
||||||
|
|
||||||
|
List<WatermarkResponseModel> result =
|
||||||
|
await handler.Handle(new GetAllWatermarksForApi(), CancellationToken.None);
|
||||||
|
|
||||||
|
result.Count.ShouldBe(2);
|
||||||
|
result.ShouldContain(new WatermarkResponseModel(1, "Bug"));
|
||||||
|
result.ShouldContain(new WatermarkResponseModel(2, "Logo"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task GetAllWatermarksForApi_Should_Return_Empty_List_When_None_Exist()
|
||||||
|
{
|
||||||
|
var handler = new GetAllWatermarksForApiHandler(_db.Factory);
|
||||||
|
|
||||||
|
List<WatermarkResponseModel> result =
|
||||||
|
await handler.Handle(new GetAllWatermarksForApi(), CancellationToken.None);
|
||||||
|
|
||||||
|
result.ShouldBeEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SeedWatermark(int id, string name)
|
||||||
|
{
|
||||||
|
await using TvContext context = _db.CreateContext();
|
||||||
|
context.ChannelWatermarks.Add(new ChannelWatermark
|
||||||
|
{
|
||||||
|
Id = id,
|
||||||
|
Name = name,
|
||||||
|
Mode = ChannelWatermarkMode.Permanent,
|
||||||
|
ImageSource = ChannelWatermarkImageSource.Custom,
|
||||||
|
Image = "watermark.png",
|
||||||
|
Location = WatermarkLocation.BottomRight,
|
||||||
|
Size = WatermarkSize.Scaled,
|
||||||
|
WidthPercent = 10,
|
||||||
|
HorizontalMarginPercent = 2,
|
||||||
|
VerticalMarginPercent = 2,
|
||||||
|
FrequencyMinutes = 15,
|
||||||
|
DurationSeconds = 30,
|
||||||
|
Opacity = 100
|
||||||
|
});
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ namespace ErsatzTV.Controllers.Api;
|
|||||||
[ApiController]
|
[ApiController]
|
||||||
public class FillerPresetController(IMediator mediator) : ControllerBase
|
public class FillerPresetController(IMediator mediator) : ControllerBase
|
||||||
{
|
{
|
||||||
[HttpGet("/api/filler-presets")]
|
[HttpGet("/api/filler-presets", Name = "GetFillerPresets")]
|
||||||
[Tags("Filler Presets")]
|
[Tags("Filler Presets")]
|
||||||
[EndpointSummary("Get all filler presets")]
|
[EndpointSummary("Get all filler presets")]
|
||||||
[EndpointGroupName("general")]
|
[EndpointGroupName("general")]
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace ErsatzTV.Controllers.Api;
|
|||||||
[ApiController]
|
[ApiController]
|
||||||
public class GraphicsElementController(IMediator mediator) : ControllerBase
|
public class GraphicsElementController(IMediator mediator) : ControllerBase
|
||||||
{
|
{
|
||||||
[HttpGet("/api/graphics-elements")]
|
[HttpGet("/api/graphics-elements", Name = "GetGraphicsElements")]
|
||||||
[Tags("Graphics Elements")]
|
[Tags("Graphics Elements")]
|
||||||
[EndpointSummary("Get all graphics elements")]
|
[EndpointSummary("Get all graphics elements")]
|
||||||
[EndpointGroupName("general")]
|
[EndpointGroupName("general")]
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace ErsatzTV.Controllers.Api;
|
|||||||
[ApiController]
|
[ApiController]
|
||||||
public class WatermarkController(IMediator mediator) : ControllerBase
|
public class WatermarkController(IMediator mediator) : ControllerBase
|
||||||
{
|
{
|
||||||
[HttpGet("/api/watermarks")]
|
[HttpGet("/api/watermarks", Name = "GetWatermarks")]
|
||||||
[Tags("Watermarks")]
|
[Tags("Watermarks")]
|
||||||
[EndpointSummary("Get all watermarks")]
|
[EndpointSummary("Get all watermarks")]
|
||||||
[EndpointGroupName("general")]
|
[EndpointGroupName("general")]
|
||||||
|
|||||||
Reference in New Issue
Block a user