Files
natsdotnet/tests/NATS.Server.Tests/IntegrationTests.cs
Joseph Doherty 2e1e1bb341 fix: resolve slopwatch issues — add logging to empty catches and eliminate test timing delays
Replace empty catch blocks with meaningful log statements in NatsServer,
NatsClient, and Program. Add WaitForReadyAsync() to NatsServer for
deterministic server startup. Replace Task.Delay/Thread.Sleep in tests
with PING/PONG protocol flush and SubscribeCoreAsync for reliable
subscription synchronization.
2026-02-22 21:14:16 -05:00

140 lines
4.1 KiB
C#

using System.Net;
using System.Net.Sockets;
using System.Text;
using Microsoft.Extensions.Logging.Abstractions;
using NATS.Client.Core;
using NATS.Server;
namespace NATS.Server.Tests;
public class IntegrationTests : IAsyncLifetime
{
private readonly NatsServer _server;
private readonly int _port;
private readonly CancellationTokenSource _cts = new();
private Task _serverTask = null!;
public IntegrationTests()
{
_port = GetFreePort();
_server = new NatsServer(new NatsOptions { Port = _port }, NullLoggerFactory.Instance);
}
public async Task InitializeAsync()
{
_serverTask = _server.StartAsync(_cts.Token);
await _server.WaitForReadyAsync();
}
public async Task DisposeAsync()
{
await _cts.CancelAsync();
_server.Dispose();
}
private static int GetFreePort()
{
using var sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.Bind(new IPEndPoint(IPAddress.Loopback, 0));
return ((IPEndPoint)sock.LocalEndPoint!).Port;
}
private NatsConnection CreateClient()
{
var opts = new NatsOpts { Url = $"nats://127.0.0.1:{_port}" };
return new NatsConnection(opts);
}
[Fact]
public async Task PubSub_basic()
{
await using var pub = CreateClient();
await using var sub = CreateClient();
await pub.ConnectAsync();
await sub.ConnectAsync();
await using var subscription = await sub.SubscribeCoreAsync<string>("test.subject");
await sub.PingAsync();
await pub.PublishAsync("test.subject", "Hello NATS!");
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5));
var msg = await subscription.Msgs.ReadAsync(timeout.Token);
msg.Data.ShouldBe("Hello NATS!");
}
[Fact]
public async Task PubSub_wildcard_star()
{
await using var pub = CreateClient();
await using var sub = CreateClient();
await pub.ConnectAsync();
await sub.ConnectAsync();
await using var subscription = await sub.SubscribeCoreAsync<string>("test.*");
await sub.PingAsync();
await pub.PublishAsync("test.hello", "data");
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5));
var msg = await subscription.Msgs.ReadAsync(timeout.Token);
msg.Subject.ShouldBe("test.hello");
}
[Fact]
public async Task PubSub_wildcard_gt()
{
await using var pub = CreateClient();
await using var sub = CreateClient();
await pub.ConnectAsync();
await sub.ConnectAsync();
await using var subscription = await sub.SubscribeCoreAsync<string>("test.>");
await sub.PingAsync();
await pub.PublishAsync("test.foo.bar.baz", "data");
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5));
var msg = await subscription.Msgs.ReadAsync(timeout.Token);
msg.Subject.ShouldBe("test.foo.bar.baz");
}
[Fact]
public async Task PubSub_fan_out()
{
await using var pub = CreateClient();
await using var sub1 = CreateClient();
await using var sub2 = CreateClient();
await pub.ConnectAsync();
await sub1.ConnectAsync();
await sub2.ConnectAsync();
await using var s1 = await sub1.SubscribeCoreAsync<string>("fanout");
await using var s2 = await sub2.SubscribeCoreAsync<string>("fanout");
await sub1.PingAsync();
await sub2.PingAsync();
await pub.PublishAsync("fanout", "hello");
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(5));
var msg1 = await s1.Msgs.ReadAsync(timeout.Token);
var msg2 = await s2.Msgs.ReadAsync(timeout.Token);
msg1.Data.ShouldBe("hello");
msg2.Data.ShouldBe("hello");
}
[Fact]
public async Task PingPong()
{
await using var client = CreateClient();
await client.ConnectAsync();
// If we got here, the connection is alive and PING/PONG works
await client.PingAsync();
}
}