Files
jellyfin-ha-src/tests/Jellyfin.Server.Implementations.Tests/Configuration/ApplicationHostPortChangeTests.cs
unkin-agent 483c739fb1
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
report a peer's port change locally without rewriting it
Keep IConfigurationManager source-compatible for plugin implementers.
2026-09-21 00:46:16 +10:00

82 lines
3.0 KiB
C#

using Emby.Server.Implementations;
using Xunit;
namespace Jellyfin.Server.Implementations.Tests.Configuration;
/// <summary>
/// The decision <c>ApplicationHost.OnConfigurationUpdated</c> makes about a port change. The ports this
/// process bound are fixed for its lifetime and the pending-restart flag is per-process, so an instance
/// applying another instance's port change still has to notice its own binding went stale - while leaving
/// the authorization write, and the notice that follows it, to the instance that made the change.
/// </summary>
public static class ApplicationHostPortChangeTests
{
/// <summary>
/// The local case, unchanged: clear the authorization flag and report the pending restart.
/// </summary>
[Fact]
public static void LocalPortChange_ClearsAuthorizationAndRequiresRestart()
{
var outcome = ApplicationHost.EvaluatePortChange(8096, 8920, 9096, 8920, true, false);
Assert.True(outcome.RequiresRestart);
Assert.True(outcome.ClearsPortAuthorization);
}
/// <summary>
/// The cross-instance case: the peer wrote the new port and cleared the flag with it, so this
/// instance must not write, but it is still listening on the old port and has to say so.
/// </summary>
[Theory]
[InlineData(true)]
[InlineData(false)]
public static void RemotePortChange_RequiresRestartWithoutWriting(bool isPortAuthorized)
{
var outcome = ApplicationHost.EvaluatePortChange(8096, 8920, 9096, 8920, isPortAuthorized, true);
Assert.True(outcome.RequiresRestart);
Assert.False(outcome.ClearsPortAuthorization);
}
/// <summary>
/// A second update while a port change is already pending must not write the flag again, and the
/// binding is still stale.
/// </summary>
[Fact]
public static void LocalPortChange_WithAuthorizationAlreadyCleared_RequiresRestartWithoutWriting()
{
var outcome = ApplicationHost.EvaluatePortChange(8096, 8920, 9096, 8920, false, false);
Assert.True(outcome.RequiresRestart);
Assert.False(outcome.ClearsPortAuthorization);
}
/// <summary>
/// An update that leaves the ports alone is not a port change, whoever wrote it.
/// </summary>
[Theory]
[InlineData(false)]
[InlineData(true)]
public static void UnchangedPorts_DoNothing(bool isApplyingRemoteInvalidation)
{
var outcome = ApplicationHost.EvaluatePortChange(8096, 8920, 8096, 8920, true, isApplyingRemoteInvalidation);
Assert.False(outcome.RequiresRestart);
Assert.False(outcome.ClearsPortAuthorization);
}
/// <summary>
/// Nothing is decided before the ports have been bound.
/// </summary>
[Theory]
[InlineData(0, 8920)]
[InlineData(8096, 0)]
public static void UnboundPorts_DoNothing(int boundHttpPort, int boundHttpsPort)
{
var outcome = ApplicationHost.EvaluatePortChange(boundHttpPort, boundHttpsPort, 9096, 9920, true, false);
Assert.False(outcome.RequiresRestart);
Assert.False(outcome.ClearsPortAuthorization);
}
}