refactor: extract NATS.Server.Auth.Tests project
Move 50 auth/accounts/permissions/JWT/NKey test files from NATS.Server.Tests into a dedicated NATS.Server.Auth.Tests project. Update namespaces, replace private GetFreePort/ReadUntilAsync helpers with TestUtilities calls, replace Task.Delay with TaskCompletionSource in test doubles, and add InternalsVisibleTo. 690 tests pass.
This commit is contained in:
251
tests/NATS.Server.Auth.Tests/AuthIntegrationTests.cs
Normal file
251
tests/NATS.Server.Auth.Tests/AuthIntegrationTests.cs
Normal file
@@ -0,0 +1,251 @@
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using NATS.Client.Core;
|
||||
using NATS.Server;
|
||||
using NATS.Server.Auth;
|
||||
|
||||
using NATS.Server.TestUtilities;
|
||||
|
||||
namespace NATS.Server.Auth.Tests;
|
||||
|
||||
public class AuthIntegrationTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks whether any exception in the chain contains the given substring.
|
||||
/// The NATS client wraps server errors in outer NatsException messages,
|
||||
/// so the actual "Authorization Violation" may be in an inner exception.
|
||||
/// </summary>
|
||||
private static bool ExceptionChainContains(Exception ex, string substring)
|
||||
{
|
||||
Exception? current = ex;
|
||||
while (current != null)
|
||||
{
|
||||
if (current.Message.Contains(substring, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
current = current.InnerException;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static (NatsServer server, int port, CancellationTokenSource cts) StartServer(NatsOptions options)
|
||||
{
|
||||
var port = TestPortAllocator.GetFreePort();
|
||||
options.Port = port;
|
||||
var server = new NatsServer(options, NullLoggerFactory.Instance);
|
||||
var cts = new CancellationTokenSource();
|
||||
_ = server.StartAsync(cts.Token);
|
||||
return (server, port, cts);
|
||||
}
|
||||
|
||||
private static async Task<(NatsServer server, int port, CancellationTokenSource cts)> StartServerAsync(NatsOptions options)
|
||||
{
|
||||
var (server, port, cts) = StartServer(options);
|
||||
await server.WaitForReadyAsync();
|
||||
return (server, port, cts);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Token_auth_success()
|
||||
{
|
||||
var (server, port, cts) = await StartServerAsync(new NatsOptions
|
||||
{
|
||||
Authorization = "s3cr3t",
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
await using var client = new NatsConnection(new NatsOpts
|
||||
{
|
||||
Url = $"nats://s3cr3t@127.0.0.1:{port}",
|
||||
});
|
||||
await client.ConnectAsync();
|
||||
await client.PingAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
await cts.CancelAsync();
|
||||
server.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Token_auth_failure_disconnects()
|
||||
{
|
||||
var (server, port, cts) = await StartServerAsync(new NatsOptions
|
||||
{
|
||||
Authorization = "s3cr3t",
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
await using var client = new NatsConnection(new NatsOpts
|
||||
{
|
||||
Url = $"nats://wrongtoken@127.0.0.1:{port}",
|
||||
MaxReconnectRetry = 0,
|
||||
});
|
||||
|
||||
var ex = await Should.ThrowAsync<NatsException>(async () =>
|
||||
{
|
||||
await client.ConnectAsync();
|
||||
await client.PingAsync();
|
||||
});
|
||||
|
||||
ExceptionChainContains(ex, "Authorization Violation").ShouldBeTrue(
|
||||
$"Expected 'Authorization Violation' in exception chain, but got: {ex}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
await cts.CancelAsync();
|
||||
server.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UserPassword_auth_success()
|
||||
{
|
||||
var (server, port, cts) = await StartServerAsync(new NatsOptions
|
||||
{
|
||||
Username = "admin",
|
||||
Password = "secret",
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
await using var client = new NatsConnection(new NatsOpts
|
||||
{
|
||||
Url = $"nats://admin:secret@127.0.0.1:{port}",
|
||||
});
|
||||
await client.ConnectAsync();
|
||||
await client.PingAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
await cts.CancelAsync();
|
||||
server.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UserPassword_auth_failure_disconnects()
|
||||
{
|
||||
var (server, port, cts) = await StartServerAsync(new NatsOptions
|
||||
{
|
||||
Username = "admin",
|
||||
Password = "secret",
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
await using var client = new NatsConnection(new NatsOpts
|
||||
{
|
||||
Url = $"nats://admin:wrong@127.0.0.1:{port}",
|
||||
MaxReconnectRetry = 0,
|
||||
});
|
||||
|
||||
var ex = await Should.ThrowAsync<NatsException>(async () =>
|
||||
{
|
||||
await client.ConnectAsync();
|
||||
await client.PingAsync();
|
||||
});
|
||||
|
||||
ExceptionChainContains(ex, "Authorization Violation").ShouldBeTrue(
|
||||
$"Expected 'Authorization Violation' in exception chain, but got: {ex}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
await cts.CancelAsync();
|
||||
server.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MultiUser_auth_success()
|
||||
{
|
||||
var (server, port, cts) = await StartServerAsync(new NatsOptions
|
||||
{
|
||||
Users =
|
||||
[
|
||||
new User { Username = "alice", Password = "pass1" },
|
||||
new User { Username = "bob", Password = "pass2" },
|
||||
],
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
await using var alice = new NatsConnection(new NatsOpts
|
||||
{
|
||||
Url = $"nats://alice:pass1@127.0.0.1:{port}",
|
||||
});
|
||||
await using var bob = new NatsConnection(new NatsOpts
|
||||
{
|
||||
Url = $"nats://bob:pass2@127.0.0.1:{port}",
|
||||
});
|
||||
|
||||
await alice.ConnectAsync();
|
||||
await alice.PingAsync();
|
||||
|
||||
await bob.ConnectAsync();
|
||||
await bob.PingAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
await cts.CancelAsync();
|
||||
server.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task No_credentials_when_auth_required_disconnects()
|
||||
{
|
||||
var (server, port, cts) = await StartServerAsync(new NatsOptions
|
||||
{
|
||||
Authorization = "s3cr3t",
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
await using var client = new NatsConnection(new NatsOpts
|
||||
{
|
||||
Url = $"nats://127.0.0.1:{port}",
|
||||
MaxReconnectRetry = 0,
|
||||
});
|
||||
|
||||
var ex = await Should.ThrowAsync<NatsException>(async () =>
|
||||
{
|
||||
await client.ConnectAsync();
|
||||
await client.PingAsync();
|
||||
});
|
||||
|
||||
ExceptionChainContains(ex, "Authorization Violation").ShouldBeTrue(
|
||||
$"Expected 'Authorization Violation' in exception chain, but got: {ex}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
await cts.CancelAsync();
|
||||
server.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task No_auth_configured_allows_all()
|
||||
{
|
||||
var (server, port, cts) = await StartServerAsync(new NatsOptions());
|
||||
|
||||
try
|
||||
{
|
||||
await using var client = new NatsConnection(new NatsOpts
|
||||
{
|
||||
Url = $"nats://127.0.0.1:{port}",
|
||||
});
|
||||
await client.ConnectAsync();
|
||||
await client.PingAsync();
|
||||
}
|
||||
finally
|
||||
{
|
||||
await cts.CancelAsync();
|
||||
server.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user