// Go: TestMonitorConnz server/monitor_test.go:367 // Go: TestMonitorConnzWithSubs server/monitor_test.go:442 // Go: TestMonitorConnzWithSubsDetail server/monitor_test.go:463 // Go: TestMonitorClosedConnzWithSubsDetail server/monitor_test.go:484 // Go: TestMonitorConnzRTT server/monitor_test.go:583 // Go: TestMonitorConnzLastActivity server/monitor_test.go:638 // Go: TestMonitorConnzWithOffsetAndLimit server/monitor_test.go:732 // Go: TestMonitorConnzDefaultSorted server/monitor_test.go:806 // Go: TestMonitorConnzSortedByCid server/monitor_test.go:827 // Go: TestMonitorConnzSortedByStart server/monitor_test.go:849 // Go: TestMonitorConnzSortedByBytesAndMsgs server/monitor_test.go:871 // Go: TestMonitorConnzSortedByPending server/monitor_test.go:925 // Go: TestMonitorConnzSortedBySubs server/monitor_test.go:950 // Go: TestMonitorConnzSortedByLast server/monitor_test.go:976 // Go: TestMonitorConnzSortedByUptime server/monitor_test.go:1007 // Go: TestMonitorConnzSortedByIdle server/monitor_test.go:1202 // Go: TestMonitorConnzSortedByStopOnOpen server/monitor_test.go:1074 // Go: TestMonitorConnzSortedByReason server/monitor_test.go:1141 // Go: TestMonitorConnzWithNamedClient server/monitor_test.go:1851 // Go: TestMonitorConnzWithStateForClosedConns server/monitor_test.go:1876 // Go: TestMonitorConcurrentMonitoring server/monitor_test.go:2148 // Go: TestMonitorConnzSortByRTT server/monitor_test.go:5979 using System.Net; using System.Net.Http.Json; using System.Net.Sockets; using Microsoft.Extensions.Logging.Abstractions; using NATS.Server.Monitoring; using NATS.Server.TestUtilities; namespace NATS.Server.Monitoring.Tests.Monitoring; /// /// Tests covering /connz endpoint behavior, ported from the Go server's monitor_test.go. /// public class MonitorConnzTests : IAsyncLifetime { private readonly NatsServer _server; private readonly int _natsPort; private readonly int _monitorPort; private readonly CancellationTokenSource _cts = new(); private readonly HttpClient _http = new(); public MonitorConnzTests() { _natsPort = TestPortAllocator.GetFreePort(); _monitorPort = TestPortAllocator.GetFreePort(); _server = new NatsServer( new NatsOptions { Port = _natsPort, MonitorPort = _monitorPort }, NullLoggerFactory.Instance); } public async Task InitializeAsync() { _ = _server.StartAsync(_cts.Token); await _server.WaitForReadyAsync(); for (var i = 0; i < 50; i++) { try { var probe = await _http.GetAsync($"http://127.0.0.1:{_monitorPort}/healthz"); if (probe.IsSuccessStatusCode) break; } catch (HttpRequestException) { } await Task.Delay(50); } } public async Task DisposeAsync() { _http.Dispose(); await _cts.CancelAsync(); _server.Dispose(); } /// /// Go: TestMonitorConnz (line 367). /// Verifies /connz returns empty connections when no clients are connected. /// [Fact] public async Task Connz_returns_empty_when_no_clients() { var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz"); connz.ShouldNotBeNull(); connz.NumConns.ShouldBe(0); connz.Total.ShouldBe(0); connz.Conns.Length.ShouldBe(0); } /// /// Go: TestMonitorConnz (line 367). /// Verifies /connz lists active connections with populated identity fields. /// [Fact] public async Task Connz_lists_active_connections_with_fields() { using var sock = await ConnectClientAsync("{\"name\":\"c1\",\"lang\":\"csharp\",\"version\":\"1.0\"}", "SUB foo 1\r\nPUB foo 5\r\nhello\r\n"); await Task.Delay(200); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz"); connz.ShouldNotBeNull(); connz.NumConns.ShouldBe(1); connz.Total.ShouldBe(1); connz.Conns.Length.ShouldBe(1); var ci = connz.Conns[0]; // Go: ci.IP == "127.0.0.1" ci.Ip.ShouldBe("127.0.0.1"); ci.Port.ShouldBeGreaterThan(0); ci.Cid.ShouldBeGreaterThan(0UL); ci.Name.ShouldBe("c1"); ci.Lang.ShouldBe("csharp"); ci.Version.ShouldBe("1.0"); ci.Start.ShouldBeGreaterThan(DateTime.MinValue); ci.LastActivity.ShouldBeGreaterThanOrEqualTo(ci.Start); ci.Uptime.ShouldNotBeNullOrEmpty(); ci.Idle.ShouldNotBeNullOrEmpty(); } /// /// Go: TestMonitorConnz (line 367). /// Verifies /connz default limit is 1024 and offset is 0. /// [Fact] public async Task Connz_default_limit_and_offset() { var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz"); connz.ShouldNotBeNull(); connz.Limit.ShouldBe(1024); // Go: DefaultConnListSize connz.Offset.ShouldBe(0); } /// /// Go: TestMonitorConnzWithSubs (line 442). /// Verifies /connz?subs=1 includes subscriptions list. /// [Fact] public async Task Connz_with_subs_includes_subscription_list() { using var sock = await ConnectClientAsync("{}", "SUB hello.foo 1\r\n"); await Task.Delay(200); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz?subs=1"); connz.ShouldNotBeNull(); connz.Conns.Length.ShouldBeGreaterThanOrEqualTo(1); var ci = connz.Conns[0]; // Go: len(ci.Subs) != 1 || ci.Subs[0] != "hello.foo" ci.Subs.ShouldContain("hello.foo"); } /// /// Go: TestMonitorConnzWithSubsDetail (line 463). /// Verifies /connz?subs=detail includes subscription detail objects. /// [Fact] public async Task Connz_with_subs_detail_includes_subscription_detail() { using var sock = await ConnectClientAsync("{}", "SUB hello.foo 1\r\n"); await Task.Delay(200); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz?subs=detail"); connz.ShouldNotBeNull(); connz.Conns.Length.ShouldBeGreaterThanOrEqualTo(1); var ci = connz.Conns[0]; // Go: len(ci.SubsDetail) != 1 || ci.SubsDetail[0].Subject != "hello.foo" ci.SubsDetail.Length.ShouldBeGreaterThanOrEqualTo(1); ci.SubsDetail.ShouldContain(sd => sd.Subject == "hello.foo"); } /// /// Go: TestMonitorConnzWithNamedClient (line 1851). /// Verifies /connz exposes client name set in CONNECT options. /// [Fact] public async Task Connz_shows_named_client() { using var sock = await ConnectClientAsync("{\"name\":\"test-client\"}"); await Task.Delay(200); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz"); connz.ShouldNotBeNull(); connz.Conns.Length.ShouldBe(1); connz.Conns[0].Name.ShouldBe("test-client"); } /// /// Go: TestMonitorConnzWithOffsetAndLimit (line 732). /// Verifies /connz pagination with offset and limit parameters. /// [Fact] public async Task Connz_pagination_with_offset_and_limit() { var sockets = new List(); try { for (var i = 0; i < 3; i++) sockets.Add(await ConnectClientAsync("{}")); await Task.Delay(200); // offset=1, limit=1 should return 1 connection with total of 3 var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz?offset=1&limit=1"); connz.ShouldNotBeNull(); connz.Limit.ShouldBe(1); connz.Offset.ShouldBe(1); connz.Conns.Length.ShouldBe(1); connz.NumConns.ShouldBe(1); connz.Total.ShouldBeGreaterThanOrEqualTo(3); // offset past end should return 0 var connz2 = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz?offset=10&limit=1"); connz2.ShouldNotBeNull(); connz2.Conns.Length.ShouldBe(0); connz2.NumConns.ShouldBe(0); connz2.Total.ShouldBeGreaterThanOrEqualTo(3); } finally { foreach (var s in sockets) s.Dispose(); } } /// /// Go: TestMonitorConnzDefaultSorted (line 806). /// Verifies /connz defaults to ascending CID sort order. /// [Fact] public async Task Connz_default_sorted_by_cid_ascending() { var sockets = new List(); try { for (var i = 0; i < 4; i++) sockets.Add(await ConnectClientAsync("{}")); await Task.Delay(200); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz"); connz.ShouldNotBeNull(); connz.Conns.Length.ShouldBeGreaterThanOrEqualTo(4); // Go: Conns[0].Cid < Conns[1].Cid < Conns[2].Cid < Conns[3].Cid for (var i = 1; i < connz.Conns.Length; i++) connz.Conns[i].Cid.ShouldBeGreaterThan(connz.Conns[i - 1].Cid); } finally { foreach (var s in sockets) s.Dispose(); } } /// /// Go: TestMonitorConnzSortedByCid (line 827). /// Verifies /connz?sort=cid returns connections sorted by CID. /// [Fact] public async Task Connz_sort_by_cid() { var sockets = new List(); try { for (var i = 0; i < 4; i++) sockets.Add(await ConnectClientAsync("{}")); await Task.Delay(200); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz?sort=cid"); connz.ShouldNotBeNull(); for (var i = 1; i < connz.Conns.Length; i++) connz.Conns[i].Cid.ShouldBeGreaterThan(connz.Conns[i - 1].Cid); } finally { foreach (var s in sockets) s.Dispose(); } } /// /// Go: TestMonitorConnzSortedByStart (line 849). /// Verifies /connz?sort=start returns connections sorted by start time. /// [Fact] public async Task Connz_sort_by_start() { var sockets = new List(); try { for (var i = 0; i < 3; i++) { sockets.Add(await ConnectClientAsync("{}")); await Task.Delay(10); } await Task.Delay(200); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz?sort=start"); connz.ShouldNotBeNull(); for (var i = 1; i < connz.Conns.Length; i++) connz.Conns[i].Start.ShouldBeGreaterThanOrEqualTo(connz.Conns[i - 1].Start); } finally { foreach (var s in sockets) s.Dispose(); } } /// /// Go: TestMonitorConnzSortedByBytesAndMsgs (line 871). /// Verifies /connz?sort=bytes_to returns connections sorted by out_bytes descending. /// [Fact] public async Task Connz_sort_by_bytes_to() { var sockets = new List(); try { // Subscriber first sockets.Add(await ConnectClientAsync("{}", "SUB foo 1\r\n")); // High-traffic publisher var pub = await ConnectClientAsync("{}"); sockets.Add(pub); using var ns = new NetworkStream(pub); for (var i = 0; i < 50; i++) await ns.WriteAsync("PUB foo 5\r\nhello\r\n"u8.ToArray()); await ns.FlushAsync(); // Low-traffic client sockets.Add(await ConnectClientAsync("{}")); await Task.Delay(300); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz?sort=bytes_to"); connz.ShouldNotBeNull(); connz.Conns.Length.ShouldBeGreaterThanOrEqualTo(2); // First entry should have >= out_bytes than second connz.Conns[0].OutBytes.ShouldBeGreaterThanOrEqualTo(connz.Conns[1].OutBytes); } finally { foreach (var s in sockets) s.Dispose(); } } /// /// Go: TestMonitorConnzSortedByBytesAndMsgs (line 871). /// Verifies /connz?sort=msgs_to returns connections sorted by out_msgs descending. /// [Fact] public async Task Connz_sort_by_msgs_to() { var sockets = new List(); try { sockets.Add(await ConnectClientAsync("{}", "SUB foo 1\r\n")); var pub = await ConnectClientAsync("{}"); sockets.Add(pub); using var ns = new NetworkStream(pub); for (var i = 0; i < 50; i++) await ns.WriteAsync("PUB foo 5\r\nhello\r\n"u8.ToArray()); await ns.FlushAsync(); sockets.Add(await ConnectClientAsync("{}")); await Task.Delay(300); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz?sort=msgs_to"); connz.ShouldNotBeNull(); connz.Conns.Length.ShouldBeGreaterThanOrEqualTo(2); connz.Conns[0].OutMsgs.ShouldBeGreaterThanOrEqualTo(connz.Conns[1].OutMsgs); } finally { foreach (var s in sockets) s.Dispose(); } } /// /// Go: TestMonitorConnzSortedByBytesAndMsgs (line 871). /// Verifies /connz?sort=msgs_from returns connections sorted by in_msgs descending. /// [Fact] public async Task Connz_sort_by_msgs_from() { var sockets = new List(); try { var pub = await ConnectClientAsync("{}"); sockets.Add(pub); using var ns = new NetworkStream(pub); for (var i = 0; i < 50; i++) await ns.WriteAsync("PUB foo 5\r\nhello\r\n"u8.ToArray()); await ns.FlushAsync(); sockets.Add(await ConnectClientAsync("{}")); await Task.Delay(300); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz?sort=msgs_from"); connz.ShouldNotBeNull(); connz.Conns.Length.ShouldBeGreaterThanOrEqualTo(2); connz.Conns[0].InMsgs.ShouldBeGreaterThanOrEqualTo(connz.Conns[1].InMsgs); } finally { foreach (var s in sockets) s.Dispose(); } } /// /// Go: TestMonitorConnzSortedBySubs (line 950). /// Verifies /connz?sort=subs returns connections sorted by subscription count descending. /// [Fact] public async Task Connz_sort_by_subs() { var sockets = new List(); try { // Client with many subs sockets.Add(await ConnectClientAsync("{}", "SUB a 1\r\nSUB b 2\r\nSUB c 3\r\n")); // Client with no subs sockets.Add(await ConnectClientAsync("{}")); await Task.Delay(200); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz?sort=subs"); connz.ShouldNotBeNull(); connz.Conns.Length.ShouldBeGreaterThanOrEqualTo(2); connz.Conns[0].NumSubs.ShouldBeGreaterThanOrEqualTo(connz.Conns[1].NumSubs); } finally { foreach (var s in sockets) s.Dispose(); } } /// /// Go: TestMonitorConnzSortedByLast (line 976). /// Verifies /connz?sort=last returns connections sorted by last_activity descending. /// [Fact] public async Task Connz_sort_by_last_activity() { var sockets = new List(); try { // First client connects and does something early sockets.Add(await ConnectClientAsync("{}")); await Task.Delay(50); // Second client connects later and does activity sockets.Add(await ConnectClientAsync("{}", "PUB foo 2\r\nhi\r\n")); await Task.Delay(200); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz?sort=last"); connz.ShouldNotBeNull(); connz.Conns.Length.ShouldBeGreaterThanOrEqualTo(2); connz.Conns[0].LastActivity.ShouldBeGreaterThanOrEqualTo(connz.Conns[1].LastActivity); } finally { foreach (var s in sockets) s.Dispose(); } } /// /// Go: TestMonitorConnzSortedByUptime (line 1007). /// Verifies /connz?sort=uptime returns connections sorted by uptime descending. /// [Fact] public async Task Connz_sort_by_uptime() { var sockets = new List(); try { // First client has longer uptime sockets.Add(await ConnectClientAsync("{}")); await Task.Delay(100); // Second client has shorter uptime sockets.Add(await ConnectClientAsync("{}")); await Task.Delay(200); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz?sort=uptime"); connz.ShouldNotBeNull(); connz.Conns.Length.ShouldBeGreaterThanOrEqualTo(2); // Descending by uptime means first entry started earlier connz.Conns[0].Start.ShouldBeLessThanOrEqualTo(connz.Conns[1].Start); } finally { foreach (var s in sockets) s.Dispose(); } } /// /// Go: TestMonitorConnzSortedByIdle (line 1202). /// Verifies /connz?sort=idle returns connections sorted by idle time descending. /// [Fact] public async Task Connz_sort_by_idle() { var sockets = new List(); try { // First client: older activity (more idle) sockets.Add(await ConnectClientAsync("{}")); await Task.Delay(200); // Second client: recent activity (less idle) sockets.Add(await ConnectClientAsync("{}", "PUB foo 2\r\nhi\r\n")); await Task.Delay(200); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz?sort=idle"); connz.ShouldNotBeNull(); connz.Conns.Length.ShouldBeGreaterThanOrEqualTo(2); // Idle descending: first entry has older last activity connz.Conns[0].LastActivity.ShouldBeLessThanOrEqualTo(connz.Conns[1].LastActivity); } finally { foreach (var s in sockets) s.Dispose(); } } /// /// Go: TestMonitorConnzWithStateForClosedConns (line 1876). /// Verifies /connz?state=closed returns recently disconnected clients. /// [Fact] public async Task Connz_state_closed_returns_disconnected_clients() { var sock = await ConnectClientAsync("{\"name\":\"closing-client\"}"); await Task.Delay(200); sock.Shutdown(SocketShutdown.Both); sock.Dispose(); await Task.Delay(500); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz?state=closed"); connz.ShouldNotBeNull(); connz.Conns.ShouldContain(c => c.Name == "closing-client"); var closed = connz.Conns.First(c => c.Name == "closing-client"); closed.Stop.ShouldNotBeNull(); closed.Reason.ShouldNotBeNullOrEmpty(); } /// /// Go: TestMonitorConnzSortedByStopOnOpen (line 1074). /// Verifies /connz?sort=stop&state=open falls back to CID sort without error. /// [Fact] public async Task Connz_sort_by_stop_with_open_state_falls_back_to_cid() { using var sock = await ConnectClientAsync("{}"); await Task.Delay(200); // Go: sort by stop on open state should fallback var response = await _http.GetAsync($"http://127.0.0.1:{_monitorPort}/connz?sort=stop&state=open"); response.StatusCode.ShouldBe(HttpStatusCode.OK); } /// /// Go: TestMonitorConnzSortedByReason (line 1141). /// Verifies /connz?sort=reason&state=closed sorts by close reason. /// [Fact] public async Task Connz_sort_by_reason_on_closed() { var sock = await ConnectClientAsync("{}"); await Task.Delay(100); sock.Shutdown(SocketShutdown.Both); sock.Dispose(); await Task.Delay(500); var response = await _http.GetAsync($"http://127.0.0.1:{_monitorPort}/connz?sort=reason&state=closed"); response.StatusCode.ShouldBe(HttpStatusCode.OK); } /// /// Go: TestMonitorConnzSortedByReasonOnOpen (line 1180). /// Verifies /connz?sort=reason&state=open falls back to CID sort without error. /// [Fact] public async Task Connz_sort_by_reason_with_open_state_falls_back() { using var sock = await ConnectClientAsync("{}"); await Task.Delay(200); var response = await _http.GetAsync($"http://127.0.0.1:{_monitorPort}/connz?sort=reason&state=open"); response.StatusCode.ShouldBe(HttpStatusCode.OK); } /// /// Go: TestMonitorConnzSortByRTT (line 5979). /// Verifies /connz?sort=rtt does not error. /// [Fact] public async Task Connz_sort_by_rtt_succeeds() { using var sock = await ConnectClientAsync("{}"); await Task.Delay(200); var response = await _http.GetAsync($"http://127.0.0.1:{_monitorPort}/connz?sort=rtt"); response.StatusCode.ShouldBe(HttpStatusCode.OK); } /// /// Go: TestMonitorConnz (line 367). /// Verifies /connz per-connection message stats are populated after pub/sub. /// [Fact] public async Task Connz_per_connection_message_stats() { using var sock = await ConnectClientAsync("{}", "SUB foo 1\r\nPUB foo 5\r\nhello\r\n"); await Task.Delay(200); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz"); connz.ShouldNotBeNull(); connz.Conns.Length.ShouldBe(1); var ci = connz.Conns[0]; // Go: ci.InMsgs == 1, ci.InBytes == 5 ci.InMsgs.ShouldBeGreaterThanOrEqualTo(1L); ci.InBytes.ShouldBeGreaterThanOrEqualTo(5L); } /// /// Go: TestMonitorConnzRTT (line 583). /// Verifies /connz includes RTT field for connected clients. /// [Fact] public async Task Connz_includes_rtt_field() { using var sock = await ConnectClientAsync("{}"); // Send a PING to trigger RTT measurement using var ns = new NetworkStream(sock); await ns.WriteAsync("PING\r\n"u8.ToArray()); await Task.Delay(200); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz"); connz.ShouldNotBeNull(); connz.Conns.Length.ShouldBeGreaterThanOrEqualTo(1); // RTT may or may not be populated depending on implementation, but field must exist connz.Conns[0].Rtt.ShouldNotBeNull(); } /// /// Go: TestMonitorConnzLastActivity (line 638). /// Verifies /connz last_activity is updated after message activity. /// [Fact] public async Task Connz_last_activity_updates_after_message() { using var sock = await ConnectClientAsync("{}"); await Task.Delay(100); // Record initial last activity var connz1 = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz"); var initial = connz1!.Conns[0].LastActivity; // Do more activity using var ns = new NetworkStream(sock); await ns.WriteAsync("PUB foo 5\r\nhello\r\n"u8.ToArray()); await ns.FlushAsync(); await Task.Delay(200); var connz2 = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz"); var updated = connz2!.Conns[0].LastActivity; // Activity should have updated updated.ShouldBeGreaterThanOrEqualTo(initial); } /// /// Go: TestMonitorConcurrentMonitoring (line 2148). /// Verifies concurrent /connz requests do not cause errors. /// [Fact] public async Task Connz_handles_concurrent_requests() { using var sock = await ConnectClientAsync("{}"); await Task.Delay(200); var tasks = Enumerable.Range(0, 10).Select(async _ => { var response = await _http.GetAsync($"http://127.0.0.1:{_monitorPort}/connz"); response.StatusCode.ShouldBe(HttpStatusCode.OK); }); await Task.WhenAll(tasks); } /// /// Go: TestMonitorConnz (line 367). /// Verifies /connz JSON uses correct Go-compatible field names. /// [Fact] public async Task Connz_json_uses_go_field_names() { using var sock = await ConnectClientAsync("{}"); await Task.Delay(200); var body = await _http.GetStringAsync($"http://127.0.0.1:{_monitorPort}/connz"); body.ShouldContain("\"server_id\""); body.ShouldContain("\"num_connections\""); body.ShouldContain("\"connections\""); } /// /// Go: TestMonitorConnzWithStateForClosedConns (line 1876). /// Verifies /connz?state=all returns both open and closed connections. /// [Fact] public async Task Connz_state_all_returns_both_open_and_closed() { // Connect and disconnect one client var sock = await ConnectClientAsync("{\"name\":\"will-close\"}"); await Task.Delay(100); sock.Shutdown(SocketShutdown.Both); sock.Dispose(); await Task.Delay(300); // Connect another client that stays open using var sock2 = await ConnectClientAsync("{\"name\":\"stays-open\"}"); await Task.Delay(200); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz?state=all"); connz.ShouldNotBeNull(); connz.Total.ShouldBeGreaterThanOrEqualTo(2); } /// /// Go: TestMonitorConnz (line 367). /// Verifies /connz server_id matches the server's ID. /// [Fact] public async Task Connz_server_id_matches_server() { var varz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/varz"); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz"); connz!.Id.ShouldBe(varz!.Id); } /// /// Go: TestMonitorConnzSortedByPending (line 925). /// Verifies /connz?sort=pending returns connections sorted by pending bytes descending. /// [Fact] public async Task Connz_sort_by_pending() { var sockets = new List(); try { sockets.Add(await ConnectClientAsync("{}")); sockets.Add(await ConnectClientAsync("{}")); await Task.Delay(200); var response = await _http.GetAsync($"http://127.0.0.1:{_monitorPort}/connz?sort=pending"); response.StatusCode.ShouldBe(HttpStatusCode.OK); } finally { foreach (var s in sockets) s.Dispose(); } } /// /// Go: TestMonitorConnzSortedByBytesAndMsgs (line 871). /// Verifies /connz?sort=bytes_from returns connections sorted by in_bytes descending. /// [Fact] public async Task Connz_sort_by_bytes_from() { var sockets = new List(); try { // High-traffic publisher var pub = await ConnectClientAsync("{}"); sockets.Add(pub); using var ns = new NetworkStream(pub); for (var i = 0; i < 50; i++) await ns.WriteAsync("PUB foo 5\r\nhello\r\n"u8.ToArray()); await ns.FlushAsync(); // Low-traffic client sockets.Add(await ConnectClientAsync("{}")); await Task.Delay(300); var connz = await _http.GetFromJsonAsync($"http://127.0.0.1:{_monitorPort}/connz?sort=bytes_from"); connz.ShouldNotBeNull(); connz.Conns.Length.ShouldBeGreaterThanOrEqualTo(2); connz.Conns[0].InBytes.ShouldBeGreaterThanOrEqualTo(connz.Conns[1].InBytes); } finally { foreach (var s in sockets) s.Dispose(); } } /// /// Helper to connect a raw TCP client to the NATS server, send CONNECT and optional commands, /// and return the socket. The caller is responsible for disposing the socket. /// private async Task ConnectClientAsync(string connectJson, string? extraCommands = null) { var sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); await sock.ConnectAsync(new IPEndPoint(IPAddress.Loopback, _natsPort)); var buf = new byte[4096]; _ = await sock.ReceiveAsync(buf, SocketFlags.None); // consume INFO var cmd = $"CONNECT {connectJson}\r\n"; if (extraCommands is not null) cmd += extraCommands; await sock.SendAsync(System.Text.Encoding.ASCII.GetBytes(cmd), SocketFlags.None); return sock; } }