mirror of https://github.com/ErsatzTV/ErsatzTV.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
149 lines
4.9 KiB
149 lines
4.9 KiB
using ErsatzTV.Core.FFmpeg; |
|
using ErsatzTV.Core.Interfaces.FFmpeg; |
|
using Microsoft.Extensions.Logging.Abstractions; |
|
using NSubstitute; |
|
using NUnit.Framework; |
|
using Shouldly; |
|
|
|
namespace ErsatzTV.Core.Tests.FFmpeg; |
|
|
|
[TestFixture] |
|
public class FFmpegSegmenterServiceTests |
|
{ |
|
[SetUp] |
|
public void SetUp() => _service = new FFmpegSegmenterService(NullLogger<FFmpegSegmenterService>.Instance); |
|
|
|
private FFmpegSegmenterService _service; |
|
|
|
[Test] |
|
public void TryAddWorker_Should_Fail_For_Second_Worker_On_Same_Channel() |
|
{ |
|
IHlsSessionWorker first = Substitute.For<IHlsSessionWorker>(); |
|
IHlsSessionWorker second = Substitute.For<IHlsSessionWorker>(); |
|
|
|
_service.TryAddWorker("1", first).ShouldBeTrue(); |
|
_service.TryAddWorker("1", second).ShouldBeFalse(); |
|
|
|
_service.TryGetWorker("1", out IHlsSessionWorker actual).ShouldBeTrue(); |
|
actual.ShouldBeSameAs(first); |
|
} |
|
|
|
[Test] |
|
public void TryAddWorker_Should_Throw_For_Null_Worker() => |
|
Should.Throw<ArgumentNullException>(() => _service.TryAddWorker("1", null)); |
|
|
|
[Test] |
|
public void TryAddWorker_Should_Not_Mark_Channel_Active_When_It_Throws() |
|
{ |
|
Should.Throw<ArgumentNullException>(() => _service.TryAddWorker("1", null)); |
|
|
|
_service.IsActive("1").ShouldBeFalse(); |
|
} |
|
|
|
[Test] |
|
public void RemoveWorker_Should_Ignore_A_Worker_That_Is_Not_Registered() |
|
{ |
|
IHlsSessionWorker current = Substitute.For<IHlsSessionWorker>(); |
|
IHlsSessionWorker stale = Substitute.For<IHlsSessionWorker>(); |
|
|
|
_service.TryAddWorker("1", current).ShouldBeTrue(); |
|
_service.RemoveWorker("1", stale); |
|
|
|
_service.IsActive("1").ShouldBeTrue(); |
|
_service.TryGetWorker("1", out IHlsSessionWorker actual).ShouldBeTrue(); |
|
actual.ShouldBeSameAs(current); |
|
} |
|
|
|
[Test] |
|
public void RemoveWorker_Should_Remove_Its_Own_Worker() |
|
{ |
|
IHlsSessionWorker worker = Substitute.For<IHlsSessionWorker>(); |
|
|
|
_service.TryAddWorker("1", worker).ShouldBeTrue(); |
|
_service.RemoveWorker("1", worker); |
|
|
|
_service.IsActive("1").ShouldBeFalse(); |
|
_service.Workers.ShouldBeEmpty(); |
|
} |
|
|
|
[Test] |
|
public void OnWorkersChanged_Should_Only_Fire_For_Effective_Changes() |
|
{ |
|
IHlsSessionWorker worker = Substitute.For<IHlsSessionWorker>(); |
|
IHlsSessionWorker other = Substitute.For<IHlsSessionWorker>(); |
|
|
|
var count = 0; |
|
_service.OnWorkersChanged += (_, _) => count++; |
|
|
|
_service.TryAddWorker("1", worker); |
|
count.ShouldBe(1); |
|
|
|
_service.TryAddWorker("1", other); |
|
count.ShouldBe(1); |
|
|
|
_service.RemoveWorker("1", other); |
|
count.ShouldBe(1); |
|
|
|
_service.RemoveWorker("1", worker); |
|
count.ShouldBe(2); |
|
} |
|
|
|
[Test] |
|
public async Task LockForStart_Should_Block_A_Second_Start_On_The_Same_Channel() |
|
{ |
|
IDisposable first = await _service.LockForStart("1", CancellationToken.None); |
|
|
|
Task<IDisposable> second = _service.LockForStart("1", CancellationToken.None); |
|
(await Task.WhenAny(second, Task.Delay(TimeSpan.FromMilliseconds(250)))).ShouldNotBe(second); |
|
|
|
first.Dispose(); |
|
|
|
IDisposable acquired = await second.WaitAsync(TimeSpan.FromSeconds(5)); |
|
acquired.Dispose(); |
|
} |
|
|
|
[Test] |
|
public async Task LockForStart_Should_Not_Block_A_Start_On_Another_Channel() |
|
{ |
|
IDisposable first = await _service.LockForStart("1", CancellationToken.None); |
|
|
|
IDisposable second = await _service.LockForStart("2", CancellationToken.None) |
|
.WaitAsync(TimeSpan.FromSeconds(5)); |
|
|
|
second.Dispose(); |
|
first.Dispose(); |
|
} |
|
|
|
[Test] |
|
public async Task LockForStart_Should_Release_When_The_Releaser_Is_Disposed_Twice() |
|
{ |
|
IDisposable first = await _service.LockForStart("1", CancellationToken.None); |
|
first.Dispose(); |
|
first.Dispose(); |
|
|
|
IDisposable second = await _service.LockForStart("1", CancellationToken.None) |
|
.WaitAsync(TimeSpan.FromSeconds(5)); |
|
|
|
// a double dispose must not leave 2 permits behind |
|
Task<IDisposable> third = _service.LockForStart("1", CancellationToken.None); |
|
(await Task.WhenAny(third, Task.Delay(TimeSpan.FromMilliseconds(250)))).ShouldNotBe(third); |
|
|
|
second.Dispose(); |
|
(await third.WaitAsync(TimeSpan.FromSeconds(5))).Dispose(); |
|
} |
|
|
|
[Test] |
|
public async Task LockForStart_Should_Throw_When_The_Token_Is_Already_Cancelled() |
|
{ |
|
IDisposable first = await _service.LockForStart("1", CancellationToken.None); |
|
|
|
using var cts = new CancellationTokenSource(); |
|
await cts.CancelAsync(); |
|
|
|
await Should.ThrowAsync<OperationCanceledException>(() => _service.LockForStart("1", cts.Token)); |
|
|
|
// the cancelled waiter must not have taken the lock |
|
first.Dispose(); |
|
(await _service.LockForStart("1", CancellationToken.None).WaitAsync(TimeSpan.FromSeconds(5))).Dispose(); |
|
} |
|
}
|
|
|