feat: add sort options to /connz (Gap 10.3)
Add ConnzSortOption enum (ConnectionId, Start, BytesTo, BytesFrom, MsgsTo, MsgsFrom, Subscriptions, Pending, Uptime, Idle, LastActivity) and ConnzSorter static class with Parse(string?) and Sort(IEnumerable<ConnInfo>, ConnzSortOption, bool) methods. Add SortBy and SortDescending properties to ConnzFilterOptions and wire them through ConnzFilterOptions.Parse (?sort= and ?desc= query params). Add 10 unit tests in ConnzSortTests covering Parse defaults, known values, unknown string fallback, and sort ordering for key fields. Go reference: server/monitor_sort_opts.go, server/monitor.go Connz().
This commit is contained in:
@@ -163,9 +163,13 @@ public sealed class SubDetail
|
|||||||
public ulong Cid { get; set; }
|
public ulong Cid { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Task 84 — account-scoped filter API (Gap 10.2)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lightweight connection info record used by the account-scoped filter API.
|
/// Lightweight connection info record used by the account-scoped filter API.
|
||||||
/// Decoupled from <see cref="ConnInfo"/> so filter logic can be tested without a running server.
|
/// Decoupled from ConnInfo so filter logic can be tested without a running server.
|
||||||
/// Go reference: monitor.go ConnInfo (subset of fields relevant to account filtering).
|
/// Go reference: monitor.go ConnInfo (subset of fields relevant to account filtering).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed record ConnzConnectionInfo(
|
public sealed record ConnzConnectionInfo(
|
||||||
@@ -180,7 +184,7 @@ public sealed record ConnzConnectionInfo(
|
|||||||
long OutBytes);
|
long OutBytes);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Paginated result returned by <see cref="ConnzFilter.ApplyFilters"/>.
|
/// Paginated result returned by ConnzFilter.ApplyFilters.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed record ConnzFilterResult(
|
public sealed record ConnzFilterResult(
|
||||||
IReadOnlyList<ConnzConnectionInfo> Connections,
|
IReadOnlyList<ConnzConnectionInfo> Connections,
|
||||||
@@ -188,30 +192,9 @@ public sealed record ConnzFilterResult(
|
|||||||
int Offset,
|
int Offset,
|
||||||
int Limit);
|
int Limit);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sort options for the /connz endpoint.
|
|
||||||
/// Go reference: monitor.go ConnzSortOpt constants.
|
|
||||||
/// </summary>
|
|
||||||
public enum ConnzSortOption
|
|
||||||
{
|
|
||||||
ConnectionId,
|
|
||||||
Start,
|
|
||||||
Subs,
|
|
||||||
Pending,
|
|
||||||
MsgsTo,
|
|
||||||
MsgsFrom,
|
|
||||||
BytesTo,
|
|
||||||
BytesFrom,
|
|
||||||
LastActivity,
|
|
||||||
Uptime,
|
|
||||||
Idle,
|
|
||||||
RTT,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Query-string options for the account-scoped filter API.
|
/// Query-string options for the account-scoped filter API.
|
||||||
/// Parses the ?acc=, ?state=, ?offset=, and ?limit= parameters that the Go server
|
/// Parses the ?acc=, ?state=, ?offset=, ?limit=, ?sort=, and ?desc= parameters.
|
||||||
/// accepts on the /connz endpoint.
|
|
||||||
/// Go reference: monitor.go ConnzOptions / Connz().
|
/// Go reference: monitor.go ConnzOptions / Connz().
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class ConnzFilterOptions
|
public sealed class ConnzFilterOptions
|
||||||
@@ -226,28 +209,25 @@ public sealed class ConnzFilterOptions
|
|||||||
public int Limit { get; init; } = 1024;
|
public int Limit { get; init; } = 1024;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sort field for connection listing. Default: <see cref="ConnzSortOption.ConnectionId"/>.
|
/// Sort field for connection listing. Default: ConnzSortOption.ConnectionId.
|
||||||
/// Go reference: monitor.go ConnzOptions.SortBy.
|
/// Go reference: monitor.go ConnzOptions.SortBy.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ConnzSortOption SortBy { get; init; } = ConnzSortOption.ConnectionId;
|
public ConnzSortOption SortBy { get; init; } = ConnzSortOption.ConnectionId;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// When <see langword="true"/>, reverses the natural sort direction for the chosen
|
/// When true, reverses the natural sort direction for the chosen SortBy option.
|
||||||
/// <see cref="SortBy"/> option.
|
|
||||||
/// Go reference: monitor.go ConnzOptions.SortBy (descending variant).
|
/// Go reference: monitor.go ConnzOptions.SortBy (descending variant).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool SortDescending { get; init; }
|
public bool SortDescending { get; init; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses a raw query string (e.g. "?acc=ACCOUNT&state=open&offset=0&limit=100&sort=bytes_to")
|
/// Parses a raw query string into a ConnzFilterOptions instance.
|
||||||
/// into a <see cref="ConnzFilterOptions"/> instance.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static ConnzFilterOptions Parse(string? queryString)
|
public static ConnzFilterOptions Parse(string? queryString)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(queryString))
|
if (string.IsNullOrEmpty(queryString))
|
||||||
return new ConnzFilterOptions();
|
return new ConnzFilterOptions();
|
||||||
|
|
||||||
// Strip leading '?'
|
|
||||||
var qs = queryString.TrimStart('?');
|
var qs = queryString.TrimStart('?');
|
||||||
|
|
||||||
string? accountFilter = null;
|
string? accountFilter = null;
|
||||||
@@ -301,29 +281,25 @@ public sealed class ConnzFilterOptions
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pure filtering helper for <see cref="ConnzConnectionInfo"/> collections.
|
/// Pure filtering helper for ConnzConnectionInfo collections.
|
||||||
/// Provides account-scoped filtering and pagination that mirror the Go server's
|
/// Provides account-scoped filtering and pagination mirroring the Go server /connz ?acc= behaviour.
|
||||||
/// /connz ?acc= behavior.
|
|
||||||
/// Go reference: monitor.go Connz() — account filter branch.
|
/// Go reference: monitor.go Connz() — account filter branch.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ConnzFilter
|
public static class ConnzFilter
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Filters <paramref name="connections"/> to only those whose
|
/// Filters connections to only those whose AccountName matches accountName
|
||||||
/// <see cref="ConnzConnectionInfo.AccountName"/> matches <paramref name="accountName"/>
|
|
||||||
/// using a case-insensitive ordinal comparison.
|
/// using a case-insensitive ordinal comparison.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IReadOnlyList<ConnzConnectionInfo> FilterByAccount(
|
public static IReadOnlyList<ConnzConnectionInfo> FilterByAccount(
|
||||||
IEnumerable<ConnzConnectionInfo> connections,
|
IEnumerable<ConnzConnectionInfo> connections,
|
||||||
string accountName)
|
string accountName) =>
|
||||||
{
|
connections
|
||||||
return connections
|
|
||||||
.Where(c => string.Equals(c.AccountName, accountName, StringComparison.OrdinalIgnoreCase))
|
.Where(c => string.Equals(c.AccountName, accountName, StringComparison.OrdinalIgnoreCase))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies all filters specified in <paramref name="options"/> and returns a paginated result.
|
/// Applies all filters specified in options and returns a paginated result.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static ConnzFilterResult ApplyFilters(
|
public static ConnzFilterResult ApplyFilters(
|
||||||
IEnumerable<ConnzConnectionInfo> connections,
|
IEnumerable<ConnzConnectionInfo> connections,
|
||||||
@@ -343,6 +319,155 @@ public static class ConnzFilter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Task 85 — sort options for /connz (Gap 10.3)
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Public sort option enum for the /connz endpoint with human-readable names.
|
||||||
|
/// Go reference: server/monitor_sort_opts.go SortOpt constants.
|
||||||
|
/// </summary>
|
||||||
|
public enum ConnzSortOption
|
||||||
|
{
|
||||||
|
/// <summary>Sort by connection ID (CID). Default.</summary>
|
||||||
|
ConnectionId,
|
||||||
|
|
||||||
|
/// <summary>Sort by connection start time (ascending by default).</summary>
|
||||||
|
Start,
|
||||||
|
|
||||||
|
/// <summary>Sort by bytes sent to the client (OutBytes), descending by default.</summary>
|
||||||
|
BytesTo,
|
||||||
|
|
||||||
|
/// <summary>Sort by bytes received from the client (InBytes), descending by default.</summary>
|
||||||
|
BytesFrom,
|
||||||
|
|
||||||
|
/// <summary>Sort by messages sent to the client (OutMsgs), descending by default.</summary>
|
||||||
|
MsgsTo,
|
||||||
|
|
||||||
|
/// <summary>Sort by messages received from the client (InMsgs), descending by default.</summary>
|
||||||
|
MsgsFrom,
|
||||||
|
|
||||||
|
/// <summary>Sort by subscription count, descending by default.</summary>
|
||||||
|
Subscriptions,
|
||||||
|
|
||||||
|
/// <summary>Sort by pending bytes, descending by default.</summary>
|
||||||
|
Pending,
|
||||||
|
|
||||||
|
/// <summary>Sort by connection duration (longest first), descending by default.</summary>
|
||||||
|
Uptime,
|
||||||
|
|
||||||
|
/// <summary>Sort by idle time (most idle first), descending by default.</summary>
|
||||||
|
Idle,
|
||||||
|
|
||||||
|
/// <summary>Sort by last activity time, descending by default.</summary>
|
||||||
|
LastActivity,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides parsing and sorting utilities for ConnInfo collections based on ConnzSortOption.
|
||||||
|
/// Go reference: server/monitor_sort_opts.go, server/monitor.go Connz().
|
||||||
|
/// </summary>
|
||||||
|
public static class ConnzSorter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Parses a query-string sort parameter to ConnzSortOption.
|
||||||
|
/// Returns ConnzSortOption.ConnectionId for null, empty, or unrecognised values.
|
||||||
|
/// Go reference: server/monitor_sort_opts.go UnmarshalJSON.
|
||||||
|
/// </summary>
|
||||||
|
public static ConnzSortOption Parse(string? sortBy) =>
|
||||||
|
sortBy?.ToLowerInvariant() switch
|
||||||
|
{
|
||||||
|
"start" => ConnzSortOption.Start,
|
||||||
|
"bytes_to" => ConnzSortOption.BytesTo,
|
||||||
|
"bytes_from" => ConnzSortOption.BytesFrom,
|
||||||
|
"msgs_to" => ConnzSortOption.MsgsTo,
|
||||||
|
"msgs_from" => ConnzSortOption.MsgsFrom,
|
||||||
|
"subs" => ConnzSortOption.Subscriptions,
|
||||||
|
"pending" => ConnzSortOption.Pending,
|
||||||
|
"uptime" => ConnzSortOption.Uptime,
|
||||||
|
"idle" => ConnzSortOption.Idle,
|
||||||
|
"last" => ConnzSortOption.LastActivity,
|
||||||
|
_ => ConnzSortOption.ConnectionId,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sorts a collection of ConnInfo records by the specified option and direction.
|
||||||
|
/// Traffic/activity metrics default to descending (highest first); ConnectionId and Start
|
||||||
|
/// default to ascending. Setting descending=true reverses the default.
|
||||||
|
/// Go reference: monitor.go Connz() sort switch.
|
||||||
|
/// </summary>
|
||||||
|
public static IReadOnlyList<ConnInfo> Sort(
|
||||||
|
IEnumerable<ConnInfo> connections,
|
||||||
|
ConnzSortOption sortBy,
|
||||||
|
bool descending = false)
|
||||||
|
{
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
|
return sortBy switch
|
||||||
|
{
|
||||||
|
ConnzSortOption.Start =>
|
||||||
|
descending
|
||||||
|
? [.. connections.OrderByDescending(c => c.Start)]
|
||||||
|
: [.. connections.OrderBy(c => c.Start)],
|
||||||
|
|
||||||
|
ConnzSortOption.BytesTo =>
|
||||||
|
descending
|
||||||
|
? [.. connections.OrderBy(c => c.OutBytes)]
|
||||||
|
: [.. connections.OrderByDescending(c => c.OutBytes)],
|
||||||
|
|
||||||
|
ConnzSortOption.BytesFrom =>
|
||||||
|
descending
|
||||||
|
? [.. connections.OrderBy(c => c.InBytes)]
|
||||||
|
: [.. connections.OrderByDescending(c => c.InBytes)],
|
||||||
|
|
||||||
|
ConnzSortOption.MsgsTo =>
|
||||||
|
descending
|
||||||
|
? [.. connections.OrderBy(c => c.OutMsgs)]
|
||||||
|
: [.. connections.OrderByDescending(c => c.OutMsgs)],
|
||||||
|
|
||||||
|
ConnzSortOption.MsgsFrom =>
|
||||||
|
descending
|
||||||
|
? [.. connections.OrderBy(c => c.InMsgs)]
|
||||||
|
: [.. connections.OrderByDescending(c => c.InMsgs)],
|
||||||
|
|
||||||
|
ConnzSortOption.Subscriptions =>
|
||||||
|
descending
|
||||||
|
? [.. connections.OrderBy(c => c.NumSubs)]
|
||||||
|
: [.. connections.OrderByDescending(c => c.NumSubs)],
|
||||||
|
|
||||||
|
ConnzSortOption.Pending =>
|
||||||
|
descending
|
||||||
|
? [.. connections.OrderBy(c => c.Pending)]
|
||||||
|
: [.. connections.OrderByDescending(c => c.Pending)],
|
||||||
|
|
||||||
|
ConnzSortOption.Uptime =>
|
||||||
|
descending
|
||||||
|
? [.. connections.OrderBy(c => now - c.Start)]
|
||||||
|
: [.. connections.OrderByDescending(c => now - c.Start)],
|
||||||
|
|
||||||
|
ConnzSortOption.Idle =>
|
||||||
|
descending
|
||||||
|
? [.. connections.OrderBy(c => now - c.LastActivity)]
|
||||||
|
: [.. connections.OrderByDescending(c => now - c.LastActivity)],
|
||||||
|
|
||||||
|
ConnzSortOption.LastActivity =>
|
||||||
|
descending
|
||||||
|
? [.. connections.OrderBy(c => c.LastActivity)]
|
||||||
|
: [.. connections.OrderByDescending(c => c.LastActivity)],
|
||||||
|
|
||||||
|
// ConnectionId and default: ascending by CID
|
||||||
|
_ =>
|
||||||
|
descending
|
||||||
|
? [.. connections.OrderByDescending(c => c.Cid)]
|
||||||
|
: [.. connections.OrderBy(c => c.Cid)],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Internal types — used by ConnzHandler and existing sort logic
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sort options for connection listing.
|
/// Sort options for connection listing.
|
||||||
/// Corresponds to Go server/monitor_sort_opts.go SortOpt type.
|
/// Corresponds to Go server/monitor_sort_opts.go SortOpt type.
|
||||||
@@ -414,24 +539,3 @@ public sealed class ConnzOptions
|
|||||||
|
|
||||||
public int Limit { get; set; } = 1024;
|
public int Limit { get; set; } = 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Parses sort query-string values for the /connz endpoint.
|
|
||||||
/// Go reference: monitor.go ConnzSortOpt string constants.
|
|
||||||
/// </summary>
|
|
||||||
public static class ConnzSorter
|
|
||||||
{
|
|
||||||
public static ConnzSortOption Parse(string value) => value.ToLowerInvariant() switch
|
|
||||||
{
|
|
||||||
"start" or "start_time" => ConnzSortOption.Start,
|
|
||||||
"subs" => ConnzSortOption.Subs,
|
|
||||||
"pending" => ConnzSortOption.Pending,
|
|
||||||
"msgs_to" or "msgs_from" => ConnzSortOption.MsgsTo,
|
|
||||||
"bytes_to" or "bytes_from" => ConnzSortOption.BytesTo,
|
|
||||||
"last" or "last_activity" => ConnzSortOption.LastActivity,
|
|
||||||
"uptime" => ConnzSortOption.Uptime,
|
|
||||||
"idle" => ConnzSortOption.Idle,
|
|
||||||
"rtt" => ConnzSortOption.RTT,
|
|
||||||
_ => ConnzSortOption.ConnectionId,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
179
tests/NATS.Server.Tests/Monitoring/ConnzSortTests.cs
Normal file
179
tests/NATS.Server.Tests/Monitoring/ConnzSortTests.cs
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
using NATS.Server.Monitoring;
|
||||||
|
|
||||||
|
namespace NATS.Server.Tests.Monitoring;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unit tests for ConnzSortOption enum, ConnzSorter.Parse, and ConnzSorter.Sort.
|
||||||
|
/// All tests exercise the types in isolation — no running server required.
|
||||||
|
/// Go reference: monitor_test.go — TestConnzSortedByCid, TestConnzSortedByBytesTo,
|
||||||
|
/// TestConnzSortedByMsgsFrom, TestConnzSortedByStart, monitor_sort_opts.go.
|
||||||
|
/// </summary>
|
||||||
|
public class ConnzSortTests
|
||||||
|
{
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
// Helper — build a ConnInfo with specific field values
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
private static ConnInfo MakeConn(
|
||||||
|
ulong cid = 1,
|
||||||
|
long outBytes = 0,
|
||||||
|
long inBytes = 0,
|
||||||
|
long outMsgs = 0,
|
||||||
|
long inMsgs = 0,
|
||||||
|
uint numSubs = 0,
|
||||||
|
int pending = 0,
|
||||||
|
DateTime connectedAt = default,
|
||||||
|
DateTime lastActivity = default) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Cid = cid,
|
||||||
|
OutBytes = outBytes,
|
||||||
|
InBytes = inBytes,
|
||||||
|
OutMsgs = outMsgs,
|
||||||
|
InMsgs = inMsgs,
|
||||||
|
NumSubs = numSubs,
|
||||||
|
Pending = pending,
|
||||||
|
Start = connectedAt == default ? DateTime.UtcNow : connectedAt,
|
||||||
|
LastActivity = lastActivity == default ? DateTime.UtcNow : lastActivity,
|
||||||
|
};
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
// ConnzSorter.Parse tests
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_ConnectionId_Default()
|
||||||
|
{
|
||||||
|
// Go reference: monitor_sort_opts.go — empty/unknown value defaults to CID sort
|
||||||
|
ConnzSorter.Parse(null).ShouldBe(ConnzSortOption.ConnectionId);
|
||||||
|
ConnzSorter.Parse("").ShouldBe(ConnzSortOption.ConnectionId);
|
||||||
|
ConnzSorter.Parse(" ").ShouldBe(ConnzSortOption.ConnectionId);
|
||||||
|
ConnzSorter.Parse("cid").ShouldBe(ConnzSortOption.ConnectionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_BytesTo_Parsed()
|
||||||
|
{
|
||||||
|
// Go reference: monitor_sort_opts.go — "bytes_to" => ByBytesTo
|
||||||
|
ConnzSorter.Parse("bytes_to").ShouldBe(ConnzSortOption.BytesTo);
|
||||||
|
ConnzSorter.Parse("BYTES_TO").ShouldBe(ConnzSortOption.BytesTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_MsgsFrom_Parsed()
|
||||||
|
{
|
||||||
|
// Go reference: monitor_sort_opts.go — "msgs_from" => ByMsgsFrom
|
||||||
|
ConnzSorter.Parse("msgs_from").ShouldBe(ConnzSortOption.MsgsFrom);
|
||||||
|
ConnzSorter.Parse("MSGS_FROM").ShouldBe(ConnzSortOption.MsgsFrom);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_Start_Parsed()
|
||||||
|
{
|
||||||
|
// Go reference: monitor_sort_opts.go — "start" => ByStart
|
||||||
|
ConnzSorter.Parse("start").ShouldBe(ConnzSortOption.Start);
|
||||||
|
ConnzSorter.Parse("START").ShouldBe(ConnzSortOption.Start);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Parse_Unknown_ReturnsDefault()
|
||||||
|
{
|
||||||
|
// Go reference: monitor_sort_opts.go — unrecognised string falls back to CID
|
||||||
|
ConnzSorter.Parse("not_a_sort_key").ShouldBe(ConnzSortOption.ConnectionId);
|
||||||
|
ConnzSorter.Parse("xyz").ShouldBe(ConnzSortOption.ConnectionId);
|
||||||
|
ConnzSorter.Parse("RANDOM").ShouldBe(ConnzSortOption.ConnectionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
// ConnzSorter.Sort tests
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Sort_ByConnectionId_Ascending()
|
||||||
|
{
|
||||||
|
// Go reference: monitor_test.go TestConnzSortedByCid — CID ascending is default
|
||||||
|
var conns = new[]
|
||||||
|
{
|
||||||
|
MakeConn(cid: 3),
|
||||||
|
MakeConn(cid: 1),
|
||||||
|
MakeConn(cid: 2),
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = ConnzSorter.Sort(conns, ConnzSortOption.ConnectionId);
|
||||||
|
|
||||||
|
result.Count.ShouldBe(3);
|
||||||
|
result[0].Cid.ShouldBe(1UL);
|
||||||
|
result[1].Cid.ShouldBe(2UL);
|
||||||
|
result[2].Cid.ShouldBe(3UL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Sort_ByBytesTo_Descending()
|
||||||
|
{
|
||||||
|
// Go reference: monitor_test.go TestConnzSortedByBytesTo — OutBytes descending
|
||||||
|
var conns = new[]
|
||||||
|
{
|
||||||
|
MakeConn(cid: 1, outBytes: 100),
|
||||||
|
MakeConn(cid: 2, outBytes: 300),
|
||||||
|
MakeConn(cid: 3, outBytes: 200),
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = ConnzSorter.Sort(conns, ConnzSortOption.BytesTo);
|
||||||
|
|
||||||
|
result.Count.ShouldBe(3);
|
||||||
|
result[0].OutBytes.ShouldBe(300);
|
||||||
|
result[1].OutBytes.ShouldBe(200);
|
||||||
|
result[2].OutBytes.ShouldBe(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Sort_ByStart_Ascending()
|
||||||
|
{
|
||||||
|
// Go reference: monitor_test.go TestConnzSortedByStart — ConnectedAt ascending
|
||||||
|
var t0 = new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
var t1 = t0.AddMinutes(1);
|
||||||
|
var t2 = t0.AddMinutes(2);
|
||||||
|
|
||||||
|
var conns = new[]
|
||||||
|
{
|
||||||
|
MakeConn(cid: 1, connectedAt: t2),
|
||||||
|
MakeConn(cid: 2, connectedAt: t0),
|
||||||
|
MakeConn(cid: 3, connectedAt: t1),
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = ConnzSorter.Sort(conns, ConnzSortOption.Start);
|
||||||
|
|
||||||
|
result.Count.ShouldBe(3);
|
||||||
|
result[0].Start.ShouldBe(t0);
|
||||||
|
result[1].Start.ShouldBe(t1);
|
||||||
|
result[2].Start.ShouldBe(t2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Sort_ByMsgsFrom_Descending()
|
||||||
|
{
|
||||||
|
// Go reference: monitor_test.go TestConnzSortedByMsgsFrom — InMsgs descending
|
||||||
|
var conns = new[]
|
||||||
|
{
|
||||||
|
MakeConn(cid: 1, inMsgs: 50),
|
||||||
|
MakeConn(cid: 2, inMsgs: 200),
|
||||||
|
MakeConn(cid: 3, inMsgs: 10),
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = ConnzSorter.Sort(conns, ConnzSortOption.MsgsFrom);
|
||||||
|
|
||||||
|
result.Count.ShouldBe(3);
|
||||||
|
result[0].InMsgs.ShouldBe(200);
|
||||||
|
result[1].InMsgs.ShouldBe(50);
|
||||||
|
result[2].InMsgs.ShouldBe(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Sort_EmptyList_ReturnsEmpty()
|
||||||
|
{
|
||||||
|
// Sorting an empty input should not throw and should return an empty list.
|
||||||
|
var result = ConnzSorter.Sort([], ConnzSortOption.BytesTo);
|
||||||
|
|
||||||
|
result.ShouldBeEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user