Move 39 monitoring, events, and system endpoint test files from NATS.Server.Tests into a dedicated NATS.Server.Monitoring.Tests project. Update namespaces, replace private GetFreePort/ReadUntilAsync with TestUtilities shared helpers, add InternalsVisibleTo, and register in the solution file. All 439 tests pass.
241 lines
7.5 KiB
C#
241 lines
7.5 KiB
C#
// Go reference: server/monitor.go — closedClients ring buffer, ClosedState tracking.
|
|
// These tests verify the fixed-size ring buffer used to track recently closed connections
|
|
// for the /connz?state=closed monitoring endpoint.
|
|
|
|
using NATS.Server.Monitoring;
|
|
|
|
namespace NATS.Server.Monitoring.Tests.Monitoring;
|
|
|
|
public class ClosedConnectionRingBufferTests
|
|
{
|
|
// -----------------------------------------------------------------------
|
|
// Helpers
|
|
// -----------------------------------------------------------------------
|
|
|
|
private static ClosedClient MakeEntry(ulong cid, string reason = "normal") => new()
|
|
{
|
|
Cid = cid,
|
|
Ip = "127.0.0.1",
|
|
Port = 4222,
|
|
Start = DateTime.UtcNow.AddSeconds(-10),
|
|
Stop = DateTime.UtcNow,
|
|
Reason = reason,
|
|
};
|
|
|
|
// -----------------------------------------------------------------------
|
|
// 1. Add_IncreasesCount
|
|
// -----------------------------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// Adding entries should increase Count up to capacity.
|
|
/// </summary>
|
|
[Fact]
|
|
public void Add_IncreasesCount()
|
|
{
|
|
var buf = new ClosedConnectionRingBuffer(capacity: 10);
|
|
|
|
buf.Count.ShouldBe(0);
|
|
|
|
buf.Add(MakeEntry(1));
|
|
buf.Count.ShouldBe(1);
|
|
|
|
buf.Add(MakeEntry(2));
|
|
buf.Count.ShouldBe(2);
|
|
|
|
buf.Add(MakeEntry(3));
|
|
buf.Count.ShouldBe(3);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// 2. Add_RingOverwrite_CapacityNotExceeded
|
|
// -----------------------------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// When capacity is exceeded the count stays at capacity (oldest entry is overwritten).
|
|
/// </summary>
|
|
[Fact]
|
|
public void Add_RingOverwrite_CapacityNotExceeded()
|
|
{
|
|
const int capacity = 5;
|
|
var buf = new ClosedConnectionRingBuffer(capacity);
|
|
|
|
for (var i = 1; i <= capacity + 3; i++)
|
|
buf.Add(MakeEntry((ulong)i));
|
|
|
|
buf.Count.ShouldBe(capacity);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// 3. GetAll_ReturnsNewestFirst
|
|
// -----------------------------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// GetAll should return entries ordered newest-first.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetAll_ReturnsNewestFirst()
|
|
{
|
|
var buf = new ClosedConnectionRingBuffer(capacity: 10);
|
|
|
|
buf.Add(MakeEntry(1));
|
|
buf.Add(MakeEntry(2));
|
|
buf.Add(MakeEntry(3));
|
|
|
|
var all = buf.GetAll();
|
|
|
|
all.Count.ShouldBe(3);
|
|
all[0].Cid.ShouldBe(3UL); // newest
|
|
all[1].Cid.ShouldBe(2UL);
|
|
all[2].Cid.ShouldBe(1UL); // oldest
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// 4. GetAll_EmptyBuffer_ReturnsEmpty
|
|
// -----------------------------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// GetAll on an empty buffer should return an empty list.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetAll_EmptyBuffer_ReturnsEmpty()
|
|
{
|
|
var buf = new ClosedConnectionRingBuffer(capacity: 10);
|
|
|
|
var all = buf.GetAll();
|
|
|
|
all.ShouldBeEmpty();
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// 5. GetRecent_ReturnsRequestedCount
|
|
// -----------------------------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// GetRecent(n) where n <= Count should return exactly n entries.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetRecent_ReturnsRequestedCount()
|
|
{
|
|
var buf = new ClosedConnectionRingBuffer(capacity: 10);
|
|
for (var i = 1; i <= 8; i++)
|
|
buf.Add(MakeEntry((ulong)i));
|
|
|
|
var recent = buf.GetRecent(3);
|
|
|
|
recent.Count.ShouldBe(3);
|
|
recent[0].Cid.ShouldBe(8UL); // newest
|
|
recent[1].Cid.ShouldBe(7UL);
|
|
recent[2].Cid.ShouldBe(6UL);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// 6. GetRecent_LessThanAvailable_ReturnsAll
|
|
// -----------------------------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// GetRecent(n) where n > Count should return all available entries.
|
|
/// </summary>
|
|
[Fact]
|
|
public void GetRecent_LessThanAvailable_ReturnsAll()
|
|
{
|
|
var buf = new ClosedConnectionRingBuffer(capacity: 10);
|
|
|
|
buf.Add(MakeEntry(1));
|
|
buf.Add(MakeEntry(2));
|
|
|
|
var recent = buf.GetRecent(100);
|
|
|
|
recent.Count.ShouldBe(2);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// 7. TotalClosed_TracksAllAdditions
|
|
// -----------------------------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// TotalClosed should increment for every Add, even after the ring wraps around.
|
|
/// </summary>
|
|
[Fact]
|
|
public void TotalClosed_TracksAllAdditions()
|
|
{
|
|
const int capacity = 4;
|
|
var buf = new ClosedConnectionRingBuffer(capacity);
|
|
|
|
buf.TotalClosed.ShouldBe(0L);
|
|
|
|
for (var i = 1; i <= 10; i++)
|
|
buf.Add(MakeEntry((ulong)i));
|
|
|
|
buf.TotalClosed.ShouldBe(10L);
|
|
buf.Count.ShouldBe(capacity); // buffer is full but total reflects all 10
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// 8. Clear_ResetsCountAndBuffer
|
|
// -----------------------------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// Clear should reset Count to zero and GetAll should return an empty list.
|
|
/// TotalClosed is intentionally not reset because it is a running lifetime counter.
|
|
/// </summary>
|
|
[Fact]
|
|
public void Clear_ResetsCountAndBuffer()
|
|
{
|
|
var buf = new ClosedConnectionRingBuffer(capacity: 10);
|
|
|
|
buf.Add(MakeEntry(1));
|
|
buf.Add(MakeEntry(2));
|
|
buf.Add(MakeEntry(3));
|
|
buf.TotalClosed.ShouldBe(3L);
|
|
|
|
buf.Clear();
|
|
|
|
buf.Count.ShouldBe(0);
|
|
buf.GetAll().ShouldBeEmpty();
|
|
// TotalClosed is a lifetime counter; it is not reset by Clear.
|
|
buf.TotalClosed.ShouldBe(3L);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// 9. Capacity_ReturnsConfiguredSize
|
|
// -----------------------------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// Capacity should reflect the value passed to the constructor.
|
|
/// </summary>
|
|
[Fact]
|
|
public void Capacity_ReturnsConfiguredSize()
|
|
{
|
|
var buf = new ClosedConnectionRingBuffer(capacity: 42);
|
|
buf.Capacity.ShouldBe(42);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------
|
|
// 10. Add_WrapsCorrectly
|
|
// -----------------------------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// After adding capacity+1 items the oldest entry (cid=1) should no longer be present,
|
|
/// and the buffer should contain the most recent 'capacity' items.
|
|
/// </summary>
|
|
[Fact]
|
|
public void Add_WrapsCorrectly()
|
|
{
|
|
const int capacity = 5;
|
|
var buf = new ClosedConnectionRingBuffer(capacity);
|
|
|
|
for (var i = 1; i <= capacity + 1; i++)
|
|
buf.Add(MakeEntry((ulong)i));
|
|
|
|
var all = buf.GetAll();
|
|
|
|
all.Count.ShouldBe(capacity);
|
|
|
|
// cid=1 (the oldest) should have been overwritten
|
|
all.Any(e => e.Cid == 1UL).ShouldBeFalse();
|
|
|
|
// The newest entry (cid=capacity+1) should be first
|
|
all[0].Cid.ShouldBe((ulong)(capacity + 1));
|
|
}
|
|
}
|