Files
ersatztv/ErsatzTV.Tests/Application/Channels/ChannelRepositoryHealthTests.cs
T
timothyandtimothy 65c0e09179
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (push) Has been skipped
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (push) Has been skipped
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 15m30s
Build ErsatzTV Image / Functional E2E (curl contracts) (push) Successful in 15m48s
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 7m32s
Build ErsatzTV Image / Build & push image (amd64) (push) Has been cancelled
feat(415): per-channel fault detection — server-derived health object + Problems filter (#581)
Closes #415. Server-derived health object on the channel list + detail DTOs (built-timeline detection, kind-agnostic across all 5 PlayoutScheduleKind; assessable gate keyed to the owning channel's mode), single "Problems" SPA filter with per-fault badges. Supersedes #72's api.channel-health-signal decision.

Co-authored-by: Timothy <timothy.look@gmail.com>
Co-committed-by: Timothy <timothy.look@gmail.com>
2026-07-23 20:45:19 +00:00

51 lines
2.3 KiB
C#

using ErsatzTV.Core.Api.Channels;
using ErsatzTV.Core.Domain;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Data.Repositories;
using ErsatzTV.Tests.Support;
using NUnit.Framework;
using Shouldly;
namespace ErsatzTV.Tests.Application.Channels;
[TestFixture]
public class ChannelRepositoryHealthTests
{
private static readonly DateTime Now = new(2026, 7, 23, 12, 0, 0, DateTimeKind.Utc);
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 GetPlayoutUpcomingHealth_Counts_Upcoming_And_Broken()
{
await using (TvContext context = _db.CreateContext())
{
var normal = new Movie { Id = 1, State = MediaItemState.Normal };
var missing = new Movie { Id = 2, State = MediaItemState.FileNotFound };
var playout1 = new Playout { Id = 10, ChannelId = 1, Items = [] };
var playout2 = new Playout { Id = 11, ChannelId = 1, Items = [] };
context.Movies.AddRange(normal, missing);
context.Playouts.AddRange(playout1, playout2);
context.PlayoutItems.AddRange(
new PlayoutItem { Id = 100, PlayoutId = 10, MediaItemId = 1, Start = Now, Finish = Now.AddHours(1), ChapterTitle = "" },
new PlayoutItem { Id = 101, PlayoutId = 10, MediaItemId = 2, Start = Now.AddHours(1), Finish = Now.AddHours(2), ChapterTitle = "" },
new PlayoutItem { Id = 102, PlayoutId = 10, MediaItemId = 1, Start = Now.AddHours(-2), Finish = Now.AddHours(-1), ChapterTitle = "" }, // past — excluded
new PlayoutItem { Id = 103, PlayoutId = 11, MediaItemId = 1, Start = Now.AddHours(-3), Finish = Now.AddHours(-2), ChapterTitle = "" }); // playout2 all past
await context.SaveChangesAsync();
}
var repo = new ChannelRepository(_db.Factory);
Dictionary<int, PlayoutUpcoming> result =
await repo.GetPlayoutUpcomingHealth([10, 11], Now, CancellationToken.None);
result[10].TotalUpcoming.ShouldBe(2);
result[10].BrokenUpcoming.ShouldBe(1);
result.ContainsKey(11).ShouldBeFalse(); // no upcoming rows -> absent from dict
}
}