Implement BumperEndpoints and remove deprecated bumper-related functionality
Added new BumperEndpoints to the API for managing bumper templates and variants, enhancing the channel management capabilities. Removed outdated bumper-related commands and handlers from the application, streamlining the codebase and improving maintainability. Updated ChannelEndpoints to reflect these changes and ensure proper routing for the new endpoints.
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using NSubstitute;
|
||||
using TeleWave.Application.Broadcast;
|
||||
using TeleWave.Application.Broadcast.Bumpers;
|
||||
using TeleWave.Application.Common.Interfaces;
|
||||
using TeleWave.Application.Streaming;
|
||||
@@ -16,8 +15,8 @@ namespace TeleWave.Application.Tests.Broadcast;
|
||||
|
||||
/// <summary>
|
||||
/// Превью ТВ-заставки: рендерится каждый подблок блока, длительность выравнивается по длине
|
||||
/// сегмента HLS, а названия «из/в» берутся из групп этого канала — иначе превью показывало бы
|
||||
/// случайные шоу из библиотеки.
|
||||
/// сегмента HLS, а плейсхолдеры подставляются образцами выбранного канала — блок общий, но
|
||||
/// смотреть на него надо глазами конкретного канала.
|
||||
/// </summary>
|
||||
public class BumperPreviewTests
|
||||
{
|
||||
@@ -38,49 +37,49 @@ public class BumperPreviewTests
|
||||
Options.Create(new StreamingOptions { SegmentSeconds = 5 })
|
||||
);
|
||||
|
||||
private static BumperTemplate NewTemplate()
|
||||
{
|
||||
var template = BumperTemplate.Create("Блок", "Текст 1");
|
||||
template
|
||||
.Variants[0]
|
||||
.SetLines([
|
||||
BumperLine.Create(0, BumperLineStyle.Label, BumperLineColor.Accent, "СЕЙЧАС"),
|
||||
BumperLine.Create(1, BumperLineStyle.Title, BumperLineColor.Text, "{now.title}"),
|
||||
BumperLine.Create(2, BumperLineStyle.Label, BumperLineColor.Accent, "ДАЛЕЕ"),
|
||||
BumperLine.Create(3, BumperLineStyle.Title, BumperLineColor.Text, "{next.title}"),
|
||||
]);
|
||||
return template;
|
||||
}
|
||||
|
||||
private static IReadOnlyList<BumperRenderSpec> Specs(IBumperRenderer renderer) =>
|
||||
renderer
|
||||
.ReceivedCalls()
|
||||
.Select(c => c.GetArguments()[1])
|
||||
.OfType<BumperRenderSpec>()
|
||||
.ToList();
|
||||
|
||||
[Fact]
|
||||
public async Task Render_UnknownChannel_ReturnsNotFound()
|
||||
public async Task Render_UnknownTemplate_ReturnsNotFound()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
await using var db = fixture.New();
|
||||
|
||||
var result = await Handler(db)
|
||||
.Handle(
|
||||
new RenderBumperPreviewCommand(Guid.NewGuid(), Guid.NewGuid()),
|
||||
CancellationToken.None
|
||||
);
|
||||
.Handle(new RenderBumperPreviewCommand(Guid.NewGuid(), null), CancellationToken.None);
|
||||
|
||||
Assert.Equal(ChannelErrors.NotFound, result.Error);
|
||||
Assert.Equal(BumperErrors.TemplateNotFound, result.Error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Render_UnknownTemplate_ReturnsBumperTemplateNotFound()
|
||||
public async Task Render_DrawsEveryVariant_WithChannelSamplesAndAlignedDuration()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
var channel = Channel.Create("Первый", "one", T0);
|
||||
await using (var seed = fixture.New())
|
||||
{
|
||||
seed.Channels.Add(channel);
|
||||
await seed.SaveChangesAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
await using var db = fixture.New();
|
||||
var result = await Handler(db)
|
||||
.Handle(
|
||||
new RenderBumperPreviewCommand(channel.Id, Guid.NewGuid()),
|
||||
CancellationToken.None
|
||||
);
|
||||
|
||||
Assert.Equal(ChannelErrors.BumperTemplateNotFound, result.Error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Render_DrawsEveryVariant_WithChannelShowNamesAndAlignedDuration()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
var channel = Channel.Create("Первый", "one", T0);
|
||||
var template = channel.BumperTemplates[0];
|
||||
var template = NewTemplate();
|
||||
var second = template.AddVariant("Второй подблок");
|
||||
second.SetLines([
|
||||
BumperLine.Create(0, BumperLineStyle.Title, BumperLineColor.Text, "{channel}"),
|
||||
]);
|
||||
|
||||
// Шоу канала: слот сетки ссылается на группу, в группе — шоу.
|
||||
var show = Show.Create("Наше шоу", ShowKind.Series);
|
||||
@@ -105,6 +104,7 @@ public class BumperPreviewTests
|
||||
await using (var seed = fixture.New())
|
||||
{
|
||||
seed.Channels.Add(channel);
|
||||
seed.BumperTemplates.Add(template);
|
||||
seed.Shows.Add(show);
|
||||
seed.Groups.Add(group);
|
||||
seed.ScheduleTemplates.Add(grid);
|
||||
@@ -115,7 +115,7 @@ public class BumperPreviewTests
|
||||
await using var db = fixture.New();
|
||||
var result = await Handler(db, renderer)
|
||||
.Handle(
|
||||
new RenderBumperPreviewCommand(channel.Id, template.Id),
|
||||
new RenderBumperPreviewCommand(template.Id, channel.Id),
|
||||
CancellationToken.None
|
||||
);
|
||||
|
||||
@@ -136,32 +136,28 @@ public class BumperPreviewTests
|
||||
Arg.Any<CancellationToken>()
|
||||
);
|
||||
|
||||
var specs = renderer
|
||||
.ReceivedCalls()
|
||||
.Select(c => c.GetArguments()[1])
|
||||
.OfType<BumperRenderSpec>()
|
||||
.ToList();
|
||||
var specs = Specs(renderer);
|
||||
// Своего звука у блока нет: 8 секунд по умолчанию, выровненные вверх до сегмента в 5 сек.
|
||||
Assert.All(specs, s => Assert.Equal(10, s.DurationSeconds));
|
||||
Assert.All(specs, s => Assert.Equal("Наше шоу", s.NowTitle));
|
||||
// Второго шоу у канала нет — подставляется заглушка.
|
||||
Assert.All(specs, s => Assert.Equal("Второе шоу", s.NextTitle));
|
||||
Assert.All(specs, s => Assert.Null(s.BackgroundFile));
|
||||
Assert.All(specs, s => Assert.Null(s.PosterFile));
|
||||
|
||||
var nowNext = specs.First(s => s.Lines.Count == 4);
|
||||
Assert.Equal("Наше шоу", nowNext.Lines[1].Text);
|
||||
|
||||
var channelLine = specs.First(s => s.Lines.Count == 1);
|
||||
Assert.Equal("Первый", channelLine.Lines[0].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Render_WithBackgroundImage_ResolvesPathFromRegistry()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
var channel = Channel.Create("Первый", "one", T0);
|
||||
var template = channel.BumperTemplates[0];
|
||||
var template = NewTemplate();
|
||||
var image = Image.Create(ImageCategory.BumperBackground, ".png", "bg.png");
|
||||
template.SetBackgroundImage(image.Id);
|
||||
|
||||
await using (var seed = fixture.New())
|
||||
{
|
||||
seed.Channels.Add(channel);
|
||||
seed.BumperTemplates.Add(template);
|
||||
seed.Images.Add(image);
|
||||
await seed.SaveChangesAsync(CancellationToken.None);
|
||||
}
|
||||
@@ -172,19 +168,40 @@ public class BumperPreviewTests
|
||||
|
||||
await using var db = fixture.New();
|
||||
var result = await Handler(db, renderer, imageStore: imageStore)
|
||||
.Handle(
|
||||
new RenderBumperPreviewCommand(channel.Id, template.Id),
|
||||
CancellationToken.None
|
||||
);
|
||||
.Handle(new RenderBumperPreviewCommand(template.Id, null), CancellationToken.None);
|
||||
|
||||
Assert.True(result.IsSuccess);
|
||||
var spec = renderer
|
||||
.ReceivedCalls()
|
||||
.Select(c => c.GetArguments()[1])
|
||||
.OfType<BumperRenderSpec>()
|
||||
.First();
|
||||
var spec = Specs(renderer).First();
|
||||
Assert.Equal("/data/images/bg.png", spec.BackgroundFile);
|
||||
// Шоу у канала нет — обе подписи заглушечные.
|
||||
Assert.Equal("Первое шоу", spec.NowTitle);
|
||||
// Канала нет — образцы заглушечные, но кадр всё равно собирается.
|
||||
Assert.Equal("Первое шоу", spec.Lines[1].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Render_DropsLinesThatResolveToNothing()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
var template = BumperTemplate.Create("Блок", "Текст 1");
|
||||
template
|
||||
.Variants[0]
|
||||
.SetLines([
|
||||
BumperLine.Create(0, BumperLineStyle.Label, BumperLineColor.Accent, "{next.genre}"),
|
||||
BumperLine.Create(1, BumperLineStyle.Title, BumperLineColor.Text, "{next.title}"),
|
||||
]);
|
||||
|
||||
await using (var seed = fixture.New())
|
||||
{
|
||||
seed.BumperTemplates.Add(template);
|
||||
await seed.SaveChangesAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
var renderer = Substitute.For<IBumperRenderer>();
|
||||
await using var db = fixture.New();
|
||||
await Handler(db, renderer)
|
||||
.Handle(new RenderBumperPreviewCommand(template.Id, null), CancellationToken.None);
|
||||
|
||||
// Жанра у образца нет — строка схлопнулась, а не оставила дыру в кадре.
|
||||
var spec = Specs(renderer).First();
|
||||
Assert.Single(spec.Lines);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using TeleWave.Application.Broadcast;
|
||||
using TeleWave.Application.Broadcast.Bumpers;
|
||||
using TeleWave.Application.Tests.Support;
|
||||
using TeleWave.Domain.Broadcast;
|
||||
@@ -9,23 +8,25 @@ namespace TeleWave.Application.Tests.Broadcast;
|
||||
|
||||
public class BumperVariantHandlersTests
|
||||
{
|
||||
private static readonly DateTimeOffset T0 = new(2026, 1, 1, 0, 0, 0, TimeSpan.Zero);
|
||||
private static BumperTemplate NewTemplate() => BumperTemplate.Create("Блок", "Текст 1");
|
||||
|
||||
private static BumperLineDto Line(string text) =>
|
||||
new(BumperLineStyle.Title, BumperLineColor.Text, text);
|
||||
|
||||
[Fact]
|
||||
public async Task AddVariant_AutoNames_WhenBlank()
|
||||
public async Task AddVariant_StartsFromDefaultPreset()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
var channel = Channel.Create("c", "c", T0);
|
||||
var template = channel.BumperTemplates[0];
|
||||
var template = NewTemplate();
|
||||
await using (var seed = fixture.New())
|
||||
{
|
||||
seed.Channels.Add(channel);
|
||||
seed.BumperTemplates.Add(template);
|
||||
await seed.SaveChangesAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
await using var db = fixture.New();
|
||||
var result = await new AddBumperTextVariantCommandHandler(db).Handle(
|
||||
new AddBumperTextVariantCommand(channel.Id, template.Id, " "),
|
||||
var result = await new AddBumperVariantCommandHandler(db).Handle(
|
||||
new AddBumperVariantCommand(template.Id, "Текст 2"),
|
||||
CancellationToken.None
|
||||
);
|
||||
Assert.True(result.IsSuccess);
|
||||
@@ -33,60 +34,60 @@ public class BumperVariantHandlersTests
|
||||
|
||||
await using var verify = fixture.New();
|
||||
var stored = await verify
|
||||
.Channels.Include(c => c.BumperTemplates)
|
||||
.ThenInclude(t => t.Variants)
|
||||
.FirstAsync(c => c.Id == channel.Id);
|
||||
var variants = stored.BumperTemplates[0].Variants;
|
||||
Assert.Equal(2, variants.Count);
|
||||
Assert.Contains(variants, v => v.Name == "Текст 2");
|
||||
.BumperTemplates.Include(t => t.Variants)
|
||||
.FirstAsync(t => t.Id == template.Id);
|
||||
Assert.Equal(2, stored.Variants.Count);
|
||||
var added = stored.Variants.First(v => v.Name == "Текст 2");
|
||||
// Пустой подблок в редакторе выглядит поломанным — новый начинается с «Сейчас/Далее».
|
||||
Assert.Equal(4, added.Lines.Count);
|
||||
Assert.Contains(added.Lines, l => l.Text == "{next.title}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddVariant_UnknownTemplate_ReturnsNotFound()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
var channel = Channel.Create("c", "c", T0);
|
||||
await using (var seed = fixture.New())
|
||||
{
|
||||
seed.Channels.Add(channel);
|
||||
await seed.SaveChangesAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
await using var db = fixture.New();
|
||||
var result = await new AddBumperTextVariantCommandHandler(db).Handle(
|
||||
new AddBumperTextVariantCommand(channel.Id, Guid.NewGuid(), "x"),
|
||||
|
||||
var result = await new AddBumperVariantCommandHandler(db).Handle(
|
||||
new AddBumperVariantCommand(Guid.NewGuid(), "x"),
|
||||
CancellationToken.None
|
||||
);
|
||||
Assert.Equal(ChannelErrors.BumperTemplateNotFound, result.Error);
|
||||
|
||||
Assert.Equal(BumperErrors.TemplateNotFound, result.Error);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateVariant_ChangesFields()
|
||||
public async Task UpdateVariant_ReplacesLinesAndFields()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
var channel = Channel.Create("c", "c", T0);
|
||||
var template = channel.BumperTemplates[0];
|
||||
var template = NewTemplate();
|
||||
var variant = template.Variants[0];
|
||||
await using (var seed = fixture.New())
|
||||
{
|
||||
seed.Channels.Add(channel);
|
||||
seed.BumperTemplates.Add(template);
|
||||
await seed.SaveChangesAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
await using var db = fixture.New();
|
||||
var result = await new UpdateBumperTextVariantCommandHandler(db).Handle(
|
||||
new UpdateBumperTextVariantCommand(
|
||||
channel.Id,
|
||||
var result = await new UpdateBumperVariantCommandHandler(db).Handle(
|
||||
new UpdateBumperVariantCommand(
|
||||
template.Id,
|
||||
variant.Id,
|
||||
"Custom",
|
||||
BumperTextKind.Free,
|
||||
"NOW",
|
||||
"NEXT",
|
||||
"line1",
|
||||
"line2",
|
||||
BumperTrigger.Both,
|
||||
7
|
||||
new BumperVariantInput(
|
||||
"Custom",
|
||||
BumperTrigger.Both,
|
||||
BumperBackground.Template,
|
||||
7,
|
||||
[
|
||||
new BumperLineDto(
|
||||
BumperLineStyle.Label,
|
||||
BumperLineColor.Accent,
|
||||
"ДАЛЕЕ В {next.time}"
|
||||
),
|
||||
Line("{next.title}"),
|
||||
]
|
||||
)
|
||||
),
|
||||
CancellationToken.None
|
||||
);
|
||||
@@ -95,45 +96,75 @@ public class BumperVariantHandlersTests
|
||||
|
||||
await using var verify = fixture.New();
|
||||
var stored = await verify
|
||||
.Channels.Include(c => c.BumperTemplates)
|
||||
.ThenInclude(t => t.Variants)
|
||||
.FirstAsync(c => c.Id == channel.Id);
|
||||
var v = stored.BumperTemplates[0].Variants[0];
|
||||
.BumperTemplates.Include(t => t.Variants)
|
||||
.FirstAsync(t => t.Id == template.Id);
|
||||
var v = stored.Variants[0];
|
||||
Assert.Equal("Custom", v.Name);
|
||||
Assert.Equal(BumperTextKind.Free, v.Kind);
|
||||
Assert.Equal(7, v.Weight);
|
||||
Assert.Equal(BumperTrigger.Both, v.Trigger);
|
||||
Assert.Equal(BumperBackground.Template, v.Background);
|
||||
Assert.Equal(7, v.Weight);
|
||||
Assert.Equal(2, v.Lines.Count);
|
||||
Assert.Equal("ДАЛЕЕ В {next.time}", v.Lines[0].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateVariant_UnknownPlaceholder_IsRejected()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
var template = NewTemplate();
|
||||
var variant = template.Variants[0];
|
||||
await using (var seed = fixture.New())
|
||||
{
|
||||
seed.BumperTemplates.Add(template);
|
||||
await seed.SaveChangesAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
await using var db = fixture.New();
|
||||
var result = await new UpdateBumperVariantCommandHandler(db).Handle(
|
||||
new UpdateBumperVariantCommand(
|
||||
template.Id,
|
||||
variant.Id,
|
||||
new BumperVariantInput(
|
||||
"Custom",
|
||||
BumperTrigger.Both,
|
||||
BumperBackground.Template,
|
||||
1,
|
||||
[Line("Далее {next.tittle}")]
|
||||
)
|
||||
),
|
||||
CancellationToken.None
|
||||
);
|
||||
|
||||
// В эфире опечатка превратилась бы в пустоту, и заметить это было бы уже некому.
|
||||
Assert.Equal("Bumpers.UnknownPlaceholders", result.Error.Code);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RemoveVariant_CannotRemoveLast_ButRemovesExtra()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
var channel = Channel.Create("c", "c", T0);
|
||||
var template = channel.BumperTemplates[0];
|
||||
var template = NewTemplate();
|
||||
var only = template.Variants[0];
|
||||
var extra = template.AddVariant("Text 2");
|
||||
var extra = template.AddVariant("Текст 2");
|
||||
await using (var seed = fixture.New())
|
||||
{
|
||||
seed.Channels.Add(channel);
|
||||
seed.BumperTemplates.Add(template);
|
||||
await seed.SaveChangesAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
await using var db = fixture.New();
|
||||
var handler = new RemoveBumperTextVariantCommandHandler(db);
|
||||
|
||||
var okRemove = await handler.Handle(
|
||||
new RemoveBumperTextVariantCommand(channel.Id, template.Id, extra.Id),
|
||||
var okRemove = await new RemoveBumperVariantCommandHandler(db).Handle(
|
||||
new RemoveBumperVariantCommand(template.Id, extra.Id),
|
||||
CancellationToken.None
|
||||
);
|
||||
Assert.True(okRemove.IsSuccess);
|
||||
await db.SaveChangesAsync(CancellationToken.None);
|
||||
|
||||
await using var db2 = fixture.New();
|
||||
var lastGuard = await new RemoveBumperTextVariantCommandHandler(db2).Handle(
|
||||
new RemoveBumperTextVariantCommand(channel.Id, template.Id, only.Id),
|
||||
var lastGuard = await new RemoveBumperVariantCommandHandler(db2).Handle(
|
||||
new RemoveBumperVariantCommand(template.Id, only.Id),
|
||||
CancellationToken.None
|
||||
);
|
||||
Assert.Equal(ChannelErrors.CannotRemoveLastBumperTextVariant, lastGuard.Error);
|
||||
Assert.Equal(BumperErrors.CannotRemoveLastVariant, lastGuard.Error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,26 +7,23 @@ using Xunit;
|
||||
namespace TeleWave.Application.Tests.Broadcast;
|
||||
|
||||
/// <summary>
|
||||
/// Карточка канала: собственные свойства канала плюс блоки заставки с подблоками. Сетка сюда не
|
||||
/// входит — она запрашивается отдельно.
|
||||
/// Карточка канала: только собственные свойства канала. Сетка, стыки и заставки сюда не входят —
|
||||
/// они общие и запрашиваются отдельно.
|
||||
/// </summary>
|
||||
public class ChannelDetailsTests
|
||||
{
|
||||
private static readonly DateTimeOffset T0 = new(2026, 1, 1, 0, 0, 0, TimeSpan.Zero);
|
||||
|
||||
[Fact]
|
||||
public async Task GetChannel_MapsSettingsAndBumperTemplates()
|
||||
public async Task GetChannel_MapsOwnSettings()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
var channel = Channel.Create("Первый", "one", T0);
|
||||
var fillerId = Guid.NewGuid();
|
||||
var logoId = Guid.NewGuid();
|
||||
channel.UpdateSettings("Первый", isEnabled: true, bumpersEnabled: true, fillerId);
|
||||
channel.UpdateSettings("Первый", isEnabled: true, fillerId);
|
||||
channel.UpdateTimeSettings(3, 120, new TimeOnly(5, 0));
|
||||
channel.UpdateBumperSettings(BumperFont.Serif, BumperSelection.Random);
|
||||
channel.UpdateViewerSettings(logoId, LogoCorner.BottomLeft, 0.4, showClock: true, 0.25);
|
||||
// Второй блок должен приехать после дефолтного — порядок задаёт позиция.
|
||||
var extra = channel.AddBumperTemplate("Ночной");
|
||||
|
||||
await using (var seed = fixture.New())
|
||||
{
|
||||
@@ -48,22 +45,11 @@ public class ChannelDetailsTests
|
||||
Assert.Equal(120, dto.UtcOffsetMinutes);
|
||||
Assert.Equal(new TimeOnly(5, 0), dto.DayStartTime);
|
||||
Assert.Equal(fillerId, dto.FillerAssetId);
|
||||
Assert.True(dto.BumpersEnabled);
|
||||
Assert.Equal(BumperFont.Serif, dto.Bumper.Font);
|
||||
Assert.Equal(BumperSelection.Random, dto.Bumper.Selection);
|
||||
Assert.Equal(logoId, dto.Viewer.LogoImageId);
|
||||
Assert.Equal(LogoCorner.BottomLeft, dto.Viewer.LogoCorner);
|
||||
Assert.Equal(0.4, dto.Viewer.LogoOpacity);
|
||||
Assert.True(dto.Viewer.ShowClock);
|
||||
Assert.Equal(0.25, dto.Viewer.AnalogFilterStrength);
|
||||
|
||||
Assert.Equal(2, dto.BumperTemplates.Count);
|
||||
Assert.True(dto.BumperTemplates[0].IsDefault);
|
||||
Assert.Equal(extra.Id, dto.BumperTemplates[1].Id);
|
||||
Assert.Equal("Ночной", dto.BumperTemplates[1].Name);
|
||||
// Своего звука у свежего блока нет — джингл синтезируется.
|
||||
Assert.False(dto.BumperTemplates[1].HasAudio);
|
||||
Assert.NotEmpty(dto.BumperTemplates[0].Variants);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -48,14 +48,7 @@ public class ChannelHandlersTests
|
||||
|
||||
await using var db = fixture.New();
|
||||
var result = await new UpdateChannelSettingsCommandHandler(db).Handle(
|
||||
new UpdateChannelSettingsCommand(
|
||||
channel.Id,
|
||||
"c",
|
||||
true,
|
||||
true,
|
||||
new BumperSettingsInput(BumperFont.Sans, BumperSelection.WeightedRandom),
|
||||
null
|
||||
),
|
||||
new UpdateChannelSettingsCommand(channel.Id, "c2", true, null),
|
||||
CancellationToken.None
|
||||
);
|
||||
Assert.True(result.IsSuccess);
|
||||
@@ -63,7 +56,7 @@ public class ChannelHandlersTests
|
||||
|
||||
await using var verify = fixture.New();
|
||||
var stored = await verify.Channels.FindAsync(channel.Id);
|
||||
Assert.Equal(BumperFont.Sans, stored!.BumperFont);
|
||||
Assert.Equal(BumperSelection.WeightedRandom, stored.BumperSelection);
|
||||
Assert.Equal("c2", stored!.Name);
|
||||
Assert.True(stored.IsEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,8 +61,19 @@ public class QueryHandlersTests
|
||||
var fixture = new TestDb();
|
||||
var channel = Channel.Create("c", "c", T0);
|
||||
var show = Show.Create("Show A", ShowKind.Series);
|
||||
var variant = channel.BumperTemplates[0].Variants[0];
|
||||
var bumperTemplate = BumperTemplate.Create("Блок", "Текст 1");
|
||||
var variant = bumperTemplate.Variants[0];
|
||||
var asset = MediaAsset.Register("Show.A.S01E01.mkv", ".mkv", MediaSource.Upload);
|
||||
var bumperAsset = MediaAsset.RegisterGenerated("Блок: СЕЙЧАС / Show A");
|
||||
// Метка в расписании берётся из кэша заставки — там лежит ровно тот текст, что играл.
|
||||
var cache = BumperAsset.Create(
|
||||
bumperTemplate.Id,
|
||||
variant.Id,
|
||||
"sig",
|
||||
"""[{"style":"Label","color":"Accent","text":"СЕЙЧАС"},{"style":"Title","color":"Text","text":"Show A"}]""",
|
||||
null,
|
||||
bumperAsset.Id
|
||||
);
|
||||
var program = ScheduleEntry.Program(
|
||||
channel.Id,
|
||||
asset.Id,
|
||||
@@ -73,7 +84,7 @@ public class QueryHandlersTests
|
||||
);
|
||||
var bumper = ScheduleEntry.Bumper(
|
||||
channel.Id,
|
||||
Guid.NewGuid(),
|
||||
bumperAsset.Id,
|
||||
T0.AddMinutes(20),
|
||||
T0.AddMinutes(20).AddSeconds(8),
|
||||
show.Id,
|
||||
@@ -83,7 +94,10 @@ public class QueryHandlersTests
|
||||
{
|
||||
seed.Shows.Add(show);
|
||||
seed.Channels.Add(channel);
|
||||
seed.BumperTemplates.Add(bumperTemplate);
|
||||
seed.MediaAssets.Add(asset);
|
||||
seed.MediaAssets.Add(bumperAsset);
|
||||
seed.BumperAssets.Add(cache);
|
||||
seed.ScheduleEntries.Add(program);
|
||||
seed.ScheduleEntries.Add(bumper);
|
||||
await seed.SaveChangesAsync(CancellationToken.None);
|
||||
@@ -98,7 +112,8 @@ public class QueryHandlersTests
|
||||
Assert.True(result.IsSuccess);
|
||||
Assert.Equal(2, result.Value.Count);
|
||||
var bumperDto = result.Value.Single(e => e.Kind == ScheduleEntryKind.Bumper);
|
||||
Assert.NotNull(bumperDto.BumperName);
|
||||
Assert.Equal("Текст 1", bumperDto.BumperName);
|
||||
Assert.Equal("СЕЙЧАС · Show A", bumperDto.BumperText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -150,52 +165,4 @@ public class QueryHandlersTests
|
||||
);
|
||||
Assert.True(ok.IsSuccess);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddAndRemoveBumperTemplate_WorkThroughStorage()
|
||||
{
|
||||
var fixture = new TestDb();
|
||||
var channel = Channel.Create("c", "c", T0);
|
||||
await using (var seed = fixture.New())
|
||||
{
|
||||
seed.Channels.Add(channel);
|
||||
await seed.SaveChangesAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
Guid templateId;
|
||||
await using (var db = fixture.New())
|
||||
{
|
||||
var added = await new AddBumperTemplateCommandHandler(db).Handle(
|
||||
new AddBumperTemplateCommand(channel.Id, ""),
|
||||
CancellationToken.None
|
||||
);
|
||||
Assert.True(added.IsSuccess);
|
||||
templateId = added.Value;
|
||||
await db.SaveChangesAsync(CancellationToken.None);
|
||||
}
|
||||
|
||||
var storage = Substitute.For<IBumperTemplateStorage>();
|
||||
await using (var db = fixture.New())
|
||||
{
|
||||
var removed = await new RemoveBumperTemplateCommandHandler(db, storage).Handle(
|
||||
new RemoveBumperTemplateCommand(channel.Id, templateId),
|
||||
CancellationToken.None
|
||||
);
|
||||
Assert.True(removed.IsSuccess);
|
||||
}
|
||||
await storage.Received(1).DeleteTemplateAsync(templateId, Arg.Any<CancellationToken>());
|
||||
|
||||
// дефолтный блок удалить нельзя
|
||||
await using (var db = fixture.New())
|
||||
{
|
||||
var def = await db
|
||||
.Channels.Include(c => c.BumperTemplates)
|
||||
.FirstAsync(c => c.Id == channel.Id);
|
||||
var result = await new RemoveBumperTemplateCommandHandler(db, storage).Handle(
|
||||
new RemoveBumperTemplateCommand(channel.Id, def.BumperTemplates[0].Id),
|
||||
CancellationToken.None
|
||||
);
|
||||
Assert.Equal(ChannelErrors.CannotRemoveDefaultBumperTemplate, result.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user