Files
jellyfin-ha-src/tests/Jellyfin.Server.Tests/HighAvailability/JellyfinSectionConfigurationTests.cs
unkin-agent 95220e2ed6
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
fix(ha): read transcode store config from the variable form deployments set
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
2026-09-13 13:10:52 +10:00

96 lines
3.4 KiB
C#

using System;
using System.IO;
using MediaBrowser.Common.Configuration;
using Microsoft.Extensions.Configuration;
using Moq;
using Xunit;
namespace Jellyfin.Server.Tests.HighAvailability;
/// <summary>
/// The fork's own settings live under the <c>Jellyfin:*</c> configuration root and every manifest,
/// chart and document sets them as bare <c>Jellyfin__Section__Key</c> environment variables. The
/// startup configuration the host reads them from must therefore accept that form; when it does not,
/// a correctly set variable is dropped and the feature it configures stays off without any error.
/// </summary>
public sealed class JellyfinSectionConfigurationTests : IDisposable
{
private const string RedisKey = "Jellyfin:TranscodeStore:RedisConnectionString";
private const string UnprefixedVariable = "Jellyfin__TranscodeStore__RedisConnectionString";
private const string PrefixedVariable = "JELLYFIN_Jellyfin__TranscodeStore__RedisConnectionString";
private const string LeaseUnprefixedVariable = "Jellyfin__TranscodeStore__LeaseDurationSeconds";
private readonly string _configDirectory;
public JellyfinSectionConfigurationTests()
{
_configDirectory = Directory.CreateTempSubdirectory("jellyfin-config-test").FullName;
File.WriteAllText(Path.Combine(_configDirectory, "logging.default.json"), "{}");
}
public void Dispose()
{
Environment.SetEnvironmentVariable(UnprefixedVariable, null);
Environment.SetEnvironmentVariable(PrefixedVariable, null);
Environment.SetEnvironmentVariable(LeaseUnprefixedVariable, null);
Directory.Delete(_configDirectory, true);
}
[Fact]
public void CreateAppConfiguration_Should_Read_UnprefixedVariable()
{
Environment.SetEnvironmentVariable(UnprefixedVariable, "valkey-cheeztv-valkey:6379,abortConnect=false");
var config = CreateConfiguration();
Assert.Equal("valkey-cheeztv-valkey:6379,abortConnect=false", config[RedisKey]);
}
[Fact]
public void CreateAppConfiguration_Should_Read_UnprefixedNonStringValue()
{
Environment.SetEnvironmentVariable(LeaseUnprefixedVariable, "45");
var config = CreateConfiguration();
Assert.Equal("45", config["Jellyfin:TranscodeStore:LeaseDurationSeconds"]);
}
[Fact]
public void CreateAppConfiguration_Should_Read_PrefixedVariable()
{
Environment.SetEnvironmentVariable(PrefixedVariable, "redis:6379");
var config = CreateConfiguration();
Assert.Equal("redis:6379", config[RedisKey]);
}
[Fact]
public void CreateAppConfiguration_Should_Prefer_PrefixedVariable()
{
Environment.SetEnvironmentVariable(UnprefixedVariable, "unprefixed:6379");
Environment.SetEnvironmentVariable(PrefixedVariable, "prefixed:6379");
var config = CreateConfiguration();
Assert.Equal("prefixed:6379", config[RedisKey]);
}
[Fact]
public void CreateAppConfiguration_Should_Leave_Key_Unset_Without_Variables()
{
var config = CreateConfiguration();
Assert.Null(config[RedisKey]);
}
private IConfiguration CreateConfiguration()
{
var appPaths = new Mock<IApplicationPaths>();
appPaths.Setup(paths => paths.ConfigurationDirectoryPath).Returns(_configDirectory);
return Program.CreateAppConfiguration(new StartupOptions(), appPaths.Object);
}
}