baa16b6586
Cleanup never matched a live session because the controller registered empty manifest and segment paths, renewal was a read-modify-write that could revert a takeover, and the takeover script compared an ISO date to a number, so it errored. - populate the session record's manifest and segment paths from the playlist path - renew the lease via a Lua compare-and-set on the owning pod - store the lease expiry as unix milliseconds so the scripts can compare it - retain the session record past its lease so an orphan can still be taken over - test the Redis store against a real Redis, including the renew-vs-takeover race - drop the live stream record nothing ever read back
81 lines
3.1 KiB
C#
81 lines
3.1 KiB
C#
using System;
|
|
using System.Reflection;
|
|
using System.Threading.Tasks;
|
|
using MediaBrowser.Controller;
|
|
using MediaBrowser.Controller.Configuration;
|
|
using MediaBrowser.Controller.Devices;
|
|
using MediaBrowser.Controller.Drawing;
|
|
using MediaBrowser.Controller.Dto;
|
|
using MediaBrowser.Controller.Events;
|
|
using MediaBrowser.Controller.Library;
|
|
using MediaBrowser.Controller.Session;
|
|
using MediaBrowser.Model.Dto;
|
|
using MediaBrowser.Model.Session;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using Moq;
|
|
using Xunit;
|
|
|
|
namespace Jellyfin.Server.Implementations.Tests.SessionManager;
|
|
|
|
public class IdlePlaybackTests
|
|
{
|
|
[Theory]
|
|
[InlineData(null, null)]
|
|
[InlineData(123456789L, 123456789L)]
|
|
public async Task CheckForIdlePlayback_StopsAtLastClientReportedPosition(long? clientPositionTicks, long? expectedPositionTicks)
|
|
{
|
|
var playbackStopped = new TaskCompletionSource<long?>(TaskCreationOptions.RunContinuationsAsynchronously);
|
|
var eventManager = new Mock<IEventManager>();
|
|
eventManager
|
|
.Setup(manager => manager.PublishAsync(It.IsAny<PlaybackStopEventArgs>()))
|
|
.Callback<PlaybackStopEventArgs>(eventArgs => playbackStopped.TrySetResult(eventArgs.PlaybackPositionTicks))
|
|
.Returns(Task.CompletedTask);
|
|
await using var sessionManager = new Emby.Server.Implementations.Session.SessionManager(
|
|
NullLogger<Emby.Server.Implementations.Session.SessionManager>.Instance,
|
|
eventManager.Object,
|
|
Mock.Of<IUserDataManager>(),
|
|
Mock.Of<IServerConfigurationManager>(),
|
|
Mock.Of<ILibraryManager>(),
|
|
Mock.Of<IUserManager>(),
|
|
Mock.Of<IMusicManager>(),
|
|
Mock.Of<IDtoService>(),
|
|
Mock.Of<IImageProcessor>(),
|
|
Mock.Of<IServerApplicationHost>(),
|
|
Mock.Of<IDeviceManager>(),
|
|
Mock.Of<IMediaSourceManager>(),
|
|
Mock.Of<IHostApplicationLifetime>());
|
|
var session = await sessionManager.LogSessionActivity(
|
|
"Test Client",
|
|
"1.0.0",
|
|
"test-device",
|
|
"Test Device",
|
|
"127.0.0.1",
|
|
null);
|
|
session.NowPlayingItem = new BaseItemDto
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Name = "Test Item"
|
|
};
|
|
session.PlayState.PositionTicks = 987654321;
|
|
|
|
if (clientPositionTicks.HasValue)
|
|
{
|
|
session.StartAutomaticProgress(new PlaybackProgressInfo
|
|
{
|
|
IsPaused = true,
|
|
PositionTicks = clientPositionTicks
|
|
});
|
|
session.StopAutomaticProgress();
|
|
}
|
|
|
|
var idlePlaybackCallback = typeof(Emby.Server.Implementations.Session.SessionManager)
|
|
.GetMethod("CheckForIdlePlayback", BindingFlags.Instance | BindingFlags.NonPublic)!;
|
|
idlePlaybackCallback.Invoke(sessionManager, new object?[] { null });
|
|
|
|
var stoppedPositionTicks = await playbackStopped.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken);
|
|
|
|
Assert.Equal(expectedPositionTicks, stoppedPositionTicks);
|
|
}
|
|
}
|