Files
natsdotnet/tests/NATS.Server.Tests/JetStream/InterestRetentionTests.cs
Joseph Doherty 955d568423 feat(stream): add InterestRetentionPolicy for per-consumer ack tracking
Implements Interest retention policy logic that tracks which consumers
are interested in each message subject and whether they have acknowledged
delivery, retaining messages until all interested consumers have acked.
Go reference: stream.go checkInterestState/noInterest.
2026-02-25 02:25:39 -05:00

92 lines
2.8 KiB
C#

using NATS.Server.JetStream;
namespace NATS.Server.Tests.JetStream;
/// <summary>
/// Tests for InterestRetentionPolicy per-consumer ack tracking.
/// Go reference: stream.go checkInterestState/noInterest.
/// </summary>
public class InterestRetentionTests
{
[Fact]
public void ShouldRetain_true_when_consumers_have_not_acked()
{
var policy = new InterestRetentionPolicy();
policy.RegisterInterest("consumer-A", "orders.>");
policy.RegisterInterest("consumer-B", "orders.>");
policy.ShouldRetain(1, "orders.new").ShouldBeTrue();
}
[Fact]
public void ShouldRetain_false_when_all_consumers_acked()
{
var policy = new InterestRetentionPolicy();
policy.RegisterInterest("consumer-A", "orders.>");
policy.RegisterInterest("consumer-B", "orders.>");
policy.AcknowledgeDelivery("consumer-A", 1);
policy.ShouldRetain(1, "orders.new").ShouldBeTrue(); // B hasn't acked
policy.AcknowledgeDelivery("consumer-B", 1);
policy.ShouldRetain(1, "orders.new").ShouldBeFalse(); // both acked
}
[Fact]
public void ShouldRetain_ignores_consumers_without_interest()
{
var policy = new InterestRetentionPolicy();
policy.RegisterInterest("consumer-A", "orders.>");
policy.RegisterInterest("consumer-B", "billing.>"); // no interest in orders
policy.AcknowledgeDelivery("consumer-A", 1);
policy.ShouldRetain(1, "orders.new").ShouldBeFalse(); // B has no interest
}
[Fact]
public void UnregisterInterest_removes_consumer()
{
var policy = new InterestRetentionPolicy();
policy.RegisterInterest("consumer-A", "x.>");
policy.RegisterInterest("consumer-B", "x.>");
policy.UnregisterInterest("consumer-B");
// Only A needs to ack
policy.AcknowledgeDelivery("consumer-A", 1);
policy.ShouldRetain(1, "x.y").ShouldBeFalse();
}
[Fact]
public void ShouldRetain_false_when_no_consumers_registered()
{
var policy = new InterestRetentionPolicy();
policy.ShouldRetain(1, "any.subject").ShouldBeFalse();
}
[Fact]
public void Multiple_sequences_tracked_independently()
{
var policy = new InterestRetentionPolicy();
policy.RegisterInterest("c1", "x.>");
policy.AcknowledgeDelivery("c1", 1);
policy.ShouldRetain(1, "x.y").ShouldBeFalse();
policy.ShouldRetain(2, "x.y").ShouldBeTrue(); // seq 2 not acked
}
[Fact]
public void ConsumerCount_tracks_registrations()
{
var policy = new InterestRetentionPolicy();
policy.ConsumerCount.ShouldBe(0);
policy.RegisterInterest("c1", "x.>");
policy.RegisterInterest("c2", "y.>");
policy.ConsumerCount.ShouldBe(2);
policy.UnregisterInterest("c1");
policy.ConsumerCount.ShouldBe(1);
}
}