aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorCody Robibero <cody@robibe.ro>2026-08-07 21:38:45 -0400
committerGitHub <noreply@github.com>2026-08-07 21:38:45 -0400
commitf9b7f2edf77f0da0263dbb7ddeb5d60971cb3a0e (patch)
tree8c4bd28137b12115cb8d558af48a2dbe5c162dbd /tests
parent4192a4dd325e4f109cab0923d33344c7133447be (diff)
parente2586eed9b04d501cd5805711cb6ad5553c1816b (diff)
Merge pull request #17536 from gnattu/fix-concurrent-racing
Fix concurrent ffmpeg segment racing
Diffstat (limited to 'tests')
-rw-r--r--tests/Jellyfin.Api.Tests/Controllers/DynamicHlsControllerTests.cs76
1 files changed, 76 insertions, 0 deletions
diff --git a/tests/Jellyfin.Api.Tests/Controllers/DynamicHlsControllerTests.cs b/tests/Jellyfin.Api.Tests/Controllers/DynamicHlsControllerTests.cs
index 1f06e8fde6..5f5f273f12 100644
--- a/tests/Jellyfin.Api.Tests/Controllers/DynamicHlsControllerTests.cs
+++ b/tests/Jellyfin.Api.Tests/Controllers/DynamicHlsControllerTests.cs
@@ -1,5 +1,9 @@
using System;
+using System.Threading;
+using System.Threading.Tasks;
using Jellyfin.Api.Controllers;
+using MediaBrowser.Controller.MediaEncoding;
+using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
namespace Jellyfin.Api.Tests.Controllers
@@ -41,5 +45,77 @@ namespace Jellyfin.Api.Tests.Controllers
return data;
}
+
+ [Fact]
+ public async Task WaitForActiveTranscodingRequests_WaitsUntilRequestCompletes()
+ {
+ var job = new TranscodingJob(NullLogger<TranscodingJob>.Instance)
+ {
+ ActiveRequestCount = 1
+ };
+
+ var waitTask = DynamicHlsController.WaitForActiveTranscodingRequests(job, CancellationToken.None);
+ Assert.False(waitTask.IsCompleted);
+
+ job.DecrementActiveRequestCount();
+
+ await waitTask;
+ }
+
+ [Fact]
+ public async Task WaitForActiveTranscodingRequests_WaitsForEveryRequest()
+ {
+ var job = new TranscodingJob(NullLogger<TranscodingJob>.Instance)
+ {
+ ActiveRequestCount = 2
+ };
+
+ var waitTask = DynamicHlsController.WaitForActiveTranscodingRequests(job, CancellationToken.None);
+ job.DecrementActiveRequestCount();
+
+ await Task.Delay(150, TestContext.Current.CancellationToken);
+ Assert.False(waitTask.IsCompleted);
+
+ job.DecrementActiveRequestCount();
+
+ await waitTask;
+ }
+
+ [Fact]
+ public async Task WaitForActiveTranscodingRequests_ReturnsWithoutAnActiveRequest()
+ {
+ var job = new TranscodingJob(NullLogger<TranscodingJob>.Instance);
+
+ await DynamicHlsController.WaitForActiveTranscodingRequests(job, CancellationToken.None);
+ await DynamicHlsController.WaitForActiveTranscodingRequests(null, CancellationToken.None);
+ }
+
+ [Fact]
+ public async Task WaitForActiveTranscodingRequests_ObservesCancellation()
+ {
+ var job = new TranscodingJob(NullLogger<TranscodingJob>.Instance)
+ {
+ ActiveRequestCount = 1
+ };
+ using var cancellationTokenSource = new CancellationTokenSource();
+
+ var waitTask = DynamicHlsController.WaitForActiveTranscodingRequests(job, cancellationTokenSource.Token);
+ await cancellationTokenSource.CancelAsync();
+
+ await Assert.ThrowsAnyAsync<OperationCanceledException>(() => waitTask);
+ }
+
+ [Fact]
+ public async Task ActiveRequestCount_UpdatesAtomically()
+ {
+ const int RequestCount = 1000;
+ var job = new TranscodingJob(NullLogger<TranscodingJob>.Instance);
+
+ await Task.WhenAll(
+ Task.Run(() => Parallel.For(0, RequestCount, _ => job.IncrementActiveRequestCount())),
+ Task.Run(() => Parallel.For(0, RequestCount, _ => job.DecrementActiveRequestCount())));
+
+ Assert.Equal(0, job.ActiveRequestCount);
+ }
}
}