Files
natsdotnet/tests/NATS.Server.Core.Tests/Configuration/AuthChangePropagationTests.cs
Joseph Doherty 7fbffffd05 refactor: rename remaining tests to NATS.Server.Core.Tests
- Rename tests/NATS.Server.Tests -> tests/NATS.Server.Core.Tests
- Update solution file, InternalsVisibleTo, and csproj references
- Remove JETSTREAM_INTEGRATION_MATRIX and NATS.NKeys from csproj (moved to JetStream.Tests and Auth.Tests)
- Update all namespaces from NATS.Server.Tests.* to NATS.Server.Core.Tests.*
- Replace private GetFreePort/ReadUntilAsync helpers with TestUtilities calls
- Fix stale namespace in Transport.Tests/NetworkingGoParityTests.cs
2026-03-12 16:14:02 -04:00

197 lines
6.1 KiB
C#

// Port of Go server/reload.go — auth change propagation tests.
// Reference: golang/nats-server/server/reload.go — authOption.Apply, usersOption.Apply.
using NATS.Server.Auth;
using NATS.Server.Configuration;
using Shouldly;
namespace NATS.Server.Core.Tests.Configuration;
public sealed class AuthChangePropagationTests
{
// ─── helpers ────────────────────────────────────────────────────
private static User MakeUser(string username, string password = "pw") =>
new() { Username = username, Password = password };
private static NatsOptions BaseOpts() => new();
// ─── tests ──────────────────────────────────────────────────────
[Fact]
public void No_changes_returns_no_changes()
{
// Same empty options → nothing changed.
var oldOpts = BaseOpts();
var newOpts = BaseOpts();
var result = ConfigReloader.PropagateAuthChanges(oldOpts, newOpts);
result.HasChanges.ShouldBeFalse();
result.UsersChanged.ShouldBeFalse();
result.AccountsChanged.ShouldBeFalse();
result.TokenChanged.ShouldBeFalse();
}
[Fact]
public void User_added_detected()
{
// Adding a user must set UsersChanged.
var oldOpts = BaseOpts();
var newOpts = BaseOpts();
newOpts.Users = [MakeUser("alice")];
var result = ConfigReloader.PropagateAuthChanges(oldOpts, newOpts);
result.UsersChanged.ShouldBeTrue();
result.HasChanges.ShouldBeTrue();
}
[Fact]
public void User_removed_detected()
{
// Removing a user must set UsersChanged.
var oldOpts = BaseOpts();
oldOpts.Users = [MakeUser("alice")];
var newOpts = BaseOpts();
var result = ConfigReloader.PropagateAuthChanges(oldOpts, newOpts);
result.UsersChanged.ShouldBeTrue();
result.HasChanges.ShouldBeTrue();
}
[Fact]
public void Account_added_detected()
{
// Adding an account must set AccountsChanged.
var oldOpts = BaseOpts();
var newOpts = BaseOpts();
newOpts.Accounts = new Dictionary<string, AccountConfig>
{
["engineering"] = new AccountConfig()
};
var result = ConfigReloader.PropagateAuthChanges(oldOpts, newOpts);
result.AccountsChanged.ShouldBeTrue();
result.HasChanges.ShouldBeTrue();
}
[Fact]
public void Token_changed_detected()
{
// Changing the Authorization token must set TokenChanged.
var oldOpts = BaseOpts();
oldOpts.Authorization = "old-secret-token";
var newOpts = BaseOpts();
newOpts.Authorization = "new-secret-token";
var result = ConfigReloader.PropagateAuthChanges(oldOpts, newOpts);
result.TokenChanged.ShouldBeTrue();
result.HasChanges.ShouldBeTrue();
}
[Fact]
public void Multiple_changes_all_flagged()
{
// Changing both users and accounts must set both flags.
var oldOpts = BaseOpts();
oldOpts.Users = [MakeUser("alice")];
oldOpts.Accounts = new Dictionary<string, AccountConfig>
{
["acct-a"] = new AccountConfig()
};
var newOpts = BaseOpts();
newOpts.Users = [MakeUser("alice"), MakeUser("bob")];
newOpts.Accounts = new Dictionary<string, AccountConfig>
{
["acct-a"] = new AccountConfig(),
["acct-b"] = new AccountConfig()
};
var result = ConfigReloader.PropagateAuthChanges(oldOpts, newOpts);
result.UsersChanged.ShouldBeTrue();
result.AccountsChanged.ShouldBeTrue();
result.HasChanges.ShouldBeTrue();
}
[Fact]
public void Same_users_different_order_no_change()
{
// Users in a different order with the same names must NOT trigger UsersChanged
// because the comparison is set-based.
var oldOpts = BaseOpts();
oldOpts.Users = [MakeUser("alice"), MakeUser("bob")];
var newOpts = BaseOpts();
newOpts.Users = [MakeUser("bob"), MakeUser("alice")];
var result = ConfigReloader.PropagateAuthChanges(oldOpts, newOpts);
result.UsersChanged.ShouldBeFalse();
result.HasChanges.ShouldBeFalse();
}
[Fact]
public void HasChanges_true_when_any_change()
{
// A single changed field (token only) is enough to set HasChanges.
var oldOpts = BaseOpts();
var newOpts = BaseOpts();
newOpts.Authorization = "token-xyz";
var result = ConfigReloader.PropagateAuthChanges(oldOpts, newOpts);
result.HasChanges.ShouldBeTrue();
}
[Fact]
public void Empty_to_non_empty_users_detected()
{
// Going from zero users to one user must be detected.
var oldOpts = BaseOpts();
// No Users assigned — null list.
var newOpts = BaseOpts();
newOpts.Users = [MakeUser("charlie")];
var result = ConfigReloader.PropagateAuthChanges(oldOpts, newOpts);
result.UsersChanged.ShouldBeTrue();
result.HasChanges.ShouldBeTrue();
}
[Fact]
public void No_auth_to_auth_detected()
{
// Going from null Authorization to a token string must be detected.
var oldOpts = BaseOpts();
// Authorization is null by default.
var newOpts = BaseOpts();
newOpts.Authorization = "brand-new-token";
var result = ConfigReloader.PropagateAuthChanges(oldOpts, newOpts);
result.TokenChanged.ShouldBeTrue();
result.HasChanges.ShouldBeTrue();
}
[Fact]
public void Same_token_no_change()
{
// The same token value on both sides must NOT flag TokenChanged.
var oldOpts = BaseOpts();
oldOpts.Authorization = "stable-token";
var newOpts = BaseOpts();
newOpts.Authorization = "stable-token";
var result = ConfigReloader.PropagateAuthChanges(oldOpts, newOpts);
result.TokenChanged.ShouldBeFalse();
result.HasChanges.ShouldBeFalse();
}
}