95220e2ed6
The startup configuration only reads JELLYFIN_ prefixed environment variables, so the bare Jellyfin__TranscodeStore__* form used by the chart, the manifests and the README is dropped and the Redis store is never registered. Nothing logs the selected store, so the fallback is invisible. - Read bare Jellyfin__* variables into the Jellyfin:* configuration root - Keep an explicit JELLYFIN_ variable winning over the bare form - Log the selected transcode session store at startup - Ping Redis once at startup and log an unreachable store at Error - Log endpoints only, never the connection string
105 lines
4.5 KiB
C#
105 lines
4.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Emby.Server.Implementations.MediaEncoding;
|
|
using Jellyfin.Server.Extensions;
|
|
using MediaBrowser.Controller.MediaEncoding;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Options;
|
|
using Xunit;
|
|
|
|
namespace Jellyfin.Server.Tests.HighAvailability;
|
|
|
|
/// <summary>
|
|
/// Which transcode session store was selected is invisible at runtime — the Redis client does not
|
|
/// abort on an unreachable server and every call site swallows failures — so the selection is
|
|
/// asserted here together with the startup log line that reports it.
|
|
/// </summary>
|
|
public sealed class TranscodeStoreRegistrationTests
|
|
{
|
|
[Fact]
|
|
public void AddTranscodeSessionStore_Should_Select_RedisStore_From_UnprefixedEnvironmentKeyShape()
|
|
{
|
|
var services = new ServiceCollection();
|
|
var logger = new RecordingLogger<TranscodeStoreRegistrationTests>();
|
|
|
|
services.AddTranscodeSessionStore(BuildConfiguration("valkey-cheeztv-valkey:6379,abortConnect=false"), logger);
|
|
|
|
Assert.Equal(typeof(RedisTranscodeSessionStore), StoreImplementation(services));
|
|
Assert.True(logger.HasEntry(LogLevel.Information, nameof(RedisTranscodeSessionStore)));
|
|
}
|
|
|
|
[Fact]
|
|
public void AddTranscodeSessionStore_Should_Select_NullStore_Without_ConnectionString()
|
|
{
|
|
var services = new ServiceCollection();
|
|
var logger = new RecordingLogger<TranscodeStoreRegistrationTests>();
|
|
|
|
services.AddTranscodeSessionStore(BuildConfiguration(null), logger);
|
|
|
|
Assert.Equal(typeof(NullTranscodeSessionStore), StoreImplementation(services));
|
|
Assert.True(logger.HasEntry(LogLevel.Information, nameof(NullTranscodeSessionStore)));
|
|
}
|
|
|
|
[Fact]
|
|
public void AddTranscodeSessionStore_Should_Log_Endpoints_Without_Password()
|
|
{
|
|
var services = new ServiceCollection();
|
|
var logger = new RecordingLogger<TranscodeStoreRegistrationTests>();
|
|
|
|
services.AddTranscodeSessionStore(BuildConfiguration("valkey:6379,password=hunter2"), logger);
|
|
|
|
var message = Assert.Single(logger.Entries, entry => entry.Level == LogLevel.Information).Message;
|
|
Assert.Contains("valkey:6379", message, StringComparison.Ordinal);
|
|
Assert.DoesNotContain("hunter2", message, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void AddTranscodeSessionStore_Should_Register_ConnectivityProbe_Only_With_Redis()
|
|
{
|
|
var withRedis = new ServiceCollection();
|
|
withRedis.AddTranscodeSessionStore(BuildConfiguration("valkey:6379"), new RecordingLogger<TranscodeStoreRegistrationTests>());
|
|
|
|
var withoutRedis = new ServiceCollection();
|
|
withoutRedis.AddTranscodeSessionStore(BuildConfiguration(null), new RecordingLogger<TranscodeStoreRegistrationTests>());
|
|
|
|
Assert.Contains(withRedis, descriptor => descriptor.ImplementationType == typeof(TranscodeStoreConnectivityProbe));
|
|
Assert.DoesNotContain(withoutRedis, descriptor => descriptor.ServiceType == typeof(IHostedService));
|
|
}
|
|
|
|
[Fact]
|
|
public void AddTranscodeSessionStore_Should_Bind_Options()
|
|
{
|
|
var services = new ServiceCollection();
|
|
var configuration = new ConfigurationBuilder()
|
|
.AddInMemoryCollection(new Dictionary<string, string?>
|
|
{
|
|
[TranscodeStoreOptions.RedisConnectionStringKey] = "valkey:6379",
|
|
["Jellyfin:TranscodeStore:LeaseDurationSeconds"] = "45"
|
|
})
|
|
.Build();
|
|
|
|
services.AddTranscodeSessionStore(configuration, new RecordingLogger<TranscodeStoreRegistrationTests>());
|
|
|
|
using var provider = services.BuildServiceProvider();
|
|
var options = provider.GetRequiredService<IOptions<TranscodeStoreOptions>>().Value;
|
|
|
|
Assert.Equal(45, options.LeaseDurationSeconds);
|
|
Assert.Equal("valkey:6379", options.RedisConnectionString);
|
|
}
|
|
|
|
private static IConfiguration BuildConfiguration(string? redisConnectionString)
|
|
=> new ConfigurationBuilder()
|
|
.AddInMemoryCollection(new Dictionary<string, string?>
|
|
{
|
|
[TranscodeStoreOptions.RedisConnectionStringKey] = redisConnectionString
|
|
})
|
|
.Build();
|
|
|
|
private static Type? StoreImplementation(IServiceCollection services)
|
|
=> services.Single(descriptor => descriptor.ServiceType == typeof(ITranscodeSessionStore)).ImplementationType;
|
|
}
|