feat: execute full-repo remaining parity closure plan

This commit is contained in:
Joseph Doherty
2026-02-23 13:08:52 -05:00
parent cbe1fa6121
commit 2b64d762f6
75 changed files with 2325 additions and 121 deletions

View File

@@ -0,0 +1,21 @@
using System.Text.Json;
namespace NATS.Server.Tests;
public class ConnzParityFieldTests
{
[Fact]
public async Task Connz_includes_identity_tls_and_proxy_parity_fields()
{
await using var fx = await MonitoringParityFixture.StartAsync();
await fx.ConnectClientAsync("u", "orders.created");
var connz = fx.GetConnz("?subs=detail");
connz.Conns.ShouldNotBeEmpty();
var json = JsonSerializer.Serialize(connz);
json.ShouldContain("tls_peer_cert_subject");
json.ShouldContain("jwt_issuer_key");
json.ShouldContain("proxy");
}
}

View File

@@ -0,0 +1,115 @@
using System.Net;
using System.Net.Sockets;
using System.Text;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging.Abstractions;
using NATS.Server.Auth;
using NATS.Server.Monitoring;
namespace NATS.Server.Tests;
public class ConnzParityFilterTests
{
[Fact]
public async Task Connz_filters_by_user_account_and_subject_and_includes_tls_peer_and_jwt_metadata()
{
await using var fx = await MonitoringParityFixture.StartAsync();
await fx.ConnectClientAsync("u", "orders.created");
await fx.ConnectClientAsync("v", "payments.created");
var connz = fx.GetConnz("?user=u&acc=A&filter_subject=orders.*&subs=detail");
connz.Conns.ShouldAllBe(c => c.Account == "A" && c.AuthorizedUser == "u");
}
}
internal sealed class MonitoringParityFixture : IAsyncDisposable
{
private readonly NatsServer _server;
private readonly CancellationTokenSource _cts;
private readonly List<TcpClient> _clients = [];
private readonly NatsOptions _options;
private MonitoringParityFixture(NatsServer server, NatsOptions options, CancellationTokenSource cts)
{
_server = server;
_options = options;
_cts = cts;
}
public static async Task<MonitoringParityFixture> StartAsync()
{
var options = new NatsOptions
{
Host = "127.0.0.1",
Port = 0,
Users =
[
new User { Username = "u", Password = "p", Account = "A" },
new User { Username = "v", Password = "p", Account = "B" },
],
};
var server = new NatsServer(options, NullLoggerFactory.Instance);
var cts = new CancellationTokenSource();
_ = server.StartAsync(cts.Token);
await server.WaitForReadyAsync();
return new MonitoringParityFixture(server, options, cts);
}
public async Task ConnectClientAsync(string username, string? subscribeSubject)
{
var client = new TcpClient();
await client.ConnectAsync(IPAddress.Loopback, _server.Port);
_clients.Add(client);
var stream = client.GetStream();
await ReadLineAsync(stream); // INFO
var connect = $"CONNECT {{\"user\":\"{username}\",\"pass\":\"p\"}}\r\n";
await stream.WriteAsync(Encoding.ASCII.GetBytes(connect));
if (!string.IsNullOrEmpty(subscribeSubject))
await stream.WriteAsync(Encoding.ASCII.GetBytes($"SUB {subscribeSubject} sid-{username}\r\n"));
await stream.FlushAsync();
await Task.Delay(30);
}
public Connz GetConnz(string queryString)
{
var ctx = new DefaultHttpContext();
ctx.Request.QueryString = new QueryString(queryString);
return new ConnzHandler(_server).HandleConnz(ctx);
}
public async Task<Varz> GetVarzAsync()
{
using var handler = new VarzHandler(_server, _options);
return await handler.HandleVarzAsync();
}
public async ValueTask DisposeAsync()
{
foreach (var client in _clients)
client.Dispose();
await _cts.CancelAsync();
_server.Dispose();
_cts.Dispose();
}
private static async Task<string> ReadLineAsync(NetworkStream stream)
{
var bytes = new List<byte>();
var one = new byte[1];
while (true)
{
var read = await stream.ReadAsync(one.AsMemory(0, 1));
if (read == 0)
break;
if (one[0] == (byte)'\n')
break;
if (one[0] != (byte)'\r')
bytes.Add(one[0]);
}
return Encoding.ASCII.GetString([.. bytes]);
}
}

View File

@@ -0,0 +1,87 @@
using System.Net;
using System.Net.Sockets;
using Microsoft.Extensions.Logging.Abstractions;
namespace NATS.Server.Tests;
public class PprofEndpointTests
{
[Fact]
public async Task Debug_pprof_endpoint_returns_profile_index_when_profport_enabled()
{
await using var fx = await PprofMonitorFixture.StartWithProfilingAsync();
var body = await fx.GetStringAsync("/debug/pprof");
body.ShouldContain("profiles");
}
}
internal sealed class PprofMonitorFixture : IAsyncDisposable
{
private readonly NatsServer _server;
private readonly CancellationTokenSource _cts;
private readonly HttpClient _http;
private readonly int _monitorPort;
private PprofMonitorFixture(NatsServer server, CancellationTokenSource cts, HttpClient http, int monitorPort)
{
_server = server;
_cts = cts;
_http = http;
_monitorPort = monitorPort;
}
public static async Task<PprofMonitorFixture> StartWithProfilingAsync()
{
var monitorPort = GetFreePort();
var options = new NatsOptions
{
Host = "127.0.0.1",
Port = 0,
MonitorPort = monitorPort,
ProfPort = monitorPort,
};
var server = new NatsServer(options, NullLoggerFactory.Instance);
var cts = new CancellationTokenSource();
_ = server.StartAsync(cts.Token);
await server.WaitForReadyAsync();
var http = new HttpClient();
for (var i = 0; i < 50; i++)
{
try
{
var response = await http.GetAsync($"http://127.0.0.1:{monitorPort}/healthz");
if (response.IsSuccessStatusCode)
break;
}
catch
{
}
await Task.Delay(50);
}
return new PprofMonitorFixture(server, cts, http, monitorPort);
}
public Task<string> GetStringAsync(string path)
{
return _http.GetStringAsync($"http://127.0.0.1:{_monitorPort}{path}");
}
public async ValueTask DisposeAsync()
{
_http.Dispose();
await _cts.CancelAsync();
_server.Dispose();
_cts.Dispose();
}
private static int GetFreePort()
{
using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(new IPEndPoint(IPAddress.Loopback, 0));
return ((IPEndPoint)socket.LocalEndPoint!).Port;
}
}

View File

@@ -0,0 +1,17 @@
namespace NATS.Server.Tests;
public class VarzSlowConsumerBreakdownTests
{
[Fact]
public async Task Varz_contains_slow_consumer_breakdown_fields()
{
await using var fx = await MonitoringParityFixture.StartAsync();
var varz = await fx.GetVarzAsync();
varz.SlowConsumerStats.ShouldNotBeNull();
varz.SlowConsumerStats.Clients.ShouldBeGreaterThanOrEqualTo((ulong)0);
varz.SlowConsumerStats.Routes.ShouldBeGreaterThanOrEqualTo((ulong)0);
varz.SlowConsumerStats.Gateways.ShouldBeGreaterThanOrEqualTo((ulong)0);
varz.SlowConsumerStats.Leafs.ShouldBeGreaterThanOrEqualTo((ulong)0);
}
}