mirror of https://github.com/ErsatzTV/ErsatzTV.git
8 changed files with 182 additions and 40 deletions
@ -0,0 +1,86 @@ |
|||||||
|
using ErsatzTV.Controllers; |
||||||
|
using ErsatzTV.Core.FFmpeg; |
||||||
|
using LanguageExt; |
||||||
|
using ErsatzTV.Core.Interfaces.FFmpeg; |
||||||
|
using ErsatzTV.Core.Interfaces.Streaming; |
||||||
|
using MediatR; |
||||||
|
using Microsoft.AspNetCore.Http; |
||||||
|
using Microsoft.AspNetCore.Mvc; |
||||||
|
using Microsoft.Extensions.Logging.Abstractions; |
||||||
|
using NSubstitute; |
||||||
|
using NUnit.Framework; |
||||||
|
using Shouldly; |
||||||
|
|
||||||
|
namespace ErsatzTV.Tests.Controllers; |
||||||
|
|
||||||
|
[TestFixture] |
||||||
|
public class IptvControllerTests |
||||||
|
{ |
||||||
|
private const string ChannelNumber = "1"; |
||||||
|
|
||||||
|
[Test] |
||||||
|
public async Task GetLivePlaylist_Should_Return_Playlist_When_Trim_Succeeds() |
||||||
|
{ |
||||||
|
var trimResult = new TrimPlaylistResult(DateTimeOffset.Now, 0, 0, "#EXTM3U", 1); |
||||||
|
IptvController controller = MakeController(WorkerReturning(trimResult)); |
||||||
|
|
||||||
|
IActionResult result = await controller.GetLivePlaylist(ChannelNumber, CancellationToken.None); |
||||||
|
|
||||||
|
var content = result.ShouldBeOfType<ContentResult>(); |
||||||
|
content.Content.ShouldBe("#EXTM3U"); |
||||||
|
content.ContentType.ShouldBe("application/vnd.apple.mpegurl"); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public async Task GetLivePlaylist_Should_Ask_Client_To_Retry_When_Trim_Fails() |
||||||
|
{ |
||||||
|
IptvController controller = MakeController(WorkerReturning(Option<TrimPlaylistResult>.None)); |
||||||
|
|
||||||
|
IActionResult result = await controller.GetLivePlaylist(ChannelNumber, CancellationToken.None); |
||||||
|
|
||||||
|
// the session worker exists, so the failure is transient; a 404 would tell clients the
|
||||||
|
// stream is gone and many would abandon it instead of polling again
|
||||||
|
var statusCode = result.ShouldBeOfType<StatusCodeResult>(); |
||||||
|
statusCode.StatusCode.ShouldBe(StatusCodes.Status503ServiceUnavailable); |
||||||
|
controller.Response.Headers.RetryAfter.ToString().ShouldBe("1"); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public async Task GetLivePlaylist_Should_Redirect_To_Start_Session_When_No_Worker() |
||||||
|
{ |
||||||
|
var segmenterService = Substitute.For<IFFmpegSegmenterService>(); |
||||||
|
segmenterService.TryGetWorker(Arg.Any<string>(), out Arg.Any<IHlsSessionWorker>()).Returns(false); |
||||||
|
|
||||||
|
IActionResult result = await MakeController(segmenterService) |
||||||
|
.GetLivePlaylist(ChannelNumber, CancellationToken.None); |
||||||
|
|
||||||
|
result.ShouldBeOfType<RedirectToActionResult>() |
||||||
|
.ActionName.ShouldBe(nameof(IptvController.GetHttpLiveStreamingVideo)); |
||||||
|
} |
||||||
|
|
||||||
|
private static IFFmpegSegmenterService WorkerReturning(Option<TrimPlaylistResult> trimResult) |
||||||
|
{ |
||||||
|
var worker = Substitute.For<IHlsSessionWorker>(); |
||||||
|
worker.TrimPlaylist(Arg.Any<DateTimeOffset>(), Arg.Any<CancellationToken>()).Returns(trimResult); |
||||||
|
|
||||||
|
var segmenterService = Substitute.For<IFFmpegSegmenterService>(); |
||||||
|
segmenterService.TryGetWorker(Arg.Any<string>(), out Arg.Any<IHlsSessionWorker>()) |
||||||
|
.Returns(call => |
||||||
|
{ |
||||||
|
call[1] = worker; |
||||||
|
return true; |
||||||
|
}); |
||||||
|
|
||||||
|
return segmenterService; |
||||||
|
} |
||||||
|
|
||||||
|
private static IptvController MakeController(IFFmpegSegmenterService segmenterService) => |
||||||
|
new( |
||||||
|
Substitute.For<IMediator>(), |
||||||
|
Substitute.For<IGraphicsEngine>(), |
||||||
|
NullLogger<IptvController>.Instance, |
||||||
|
segmenterService) |
||||||
|
{ |
||||||
|
ControllerContext = new ControllerContext { HttpContext = new DefaultHttpContext() } |
||||||
|
}; |
||||||
|
} |
||||||
Loading…
Reference in new issue