Implement deferred WaitQueue, DiskAvailability, and NoOpCache behavior with tests
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
// Copyright 2012-2026 The NATS Authors
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
|
||||
using Shouldly;
|
||||
using ZB.MOM.NatsNet.Server;
|
||||
|
||||
namespace ZB.MOM.NatsNet.Server.Tests.JetStream;
|
||||
|
||||
public sealed class DiskAvailabilityTests
|
||||
{
|
||||
private const long JetStreamMaxStoreDefault = 1L * 1024 * 1024 * 1024 * 1024;
|
||||
|
||||
[Fact]
|
||||
public void DiskAvailable_MissingDirectory_ShouldCreateDirectory()
|
||||
{
|
||||
var root = Path.Combine(Path.GetTempPath(), $"disk-avail-{Guid.NewGuid():N}");
|
||||
var target = Path.Combine(root, "nested");
|
||||
try
|
||||
{
|
||||
Directory.Exists(target).ShouldBeFalse();
|
||||
|
||||
var available = DiskAvailability.DiskAvailable(target);
|
||||
|
||||
Directory.Exists(target).ShouldBeTrue();
|
||||
available.ShouldBeGreaterThan(0L);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Directory.Exists(root))
|
||||
Directory.Delete(root, recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DiskAvailable_InvalidPath_ShouldReturnFallback()
|
||||
{
|
||||
var available = DiskAvailability.DiskAvailable("\0");
|
||||
available.ShouldBe(JetStreamMaxStoreDefault);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Check_ShouldUseDiskAvailableThreshold()
|
||||
{
|
||||
var root = Path.Combine(Path.GetTempPath(), $"disk-check-{Guid.NewGuid():N}");
|
||||
try
|
||||
{
|
||||
var available = DiskAvailability.DiskAvailable(root);
|
||||
|
||||
DiskAvailability.Check(root, Math.Max(0, available - 1)).ShouldBeTrue();
|
||||
DiskAvailability.Check(root, available + 1).ShouldBeFalse();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (Directory.Exists(root))
|
||||
Directory.Delete(root, recursive: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,4 +35,82 @@ public sealed class NatsConsumerTests
|
||||
consumer.Stop();
|
||||
consumer.IsLeader().ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact] // T:1364
|
||||
public void SortingConsumerPullRequests_ShouldSucceed()
|
||||
{
|
||||
var q = new WaitQueue(max: 100);
|
||||
|
||||
q.AddPrioritized(new WaitingRequest { Reply = "1a", PriorityGroup = new PriorityGroup { Priority = 1 }, N = 1 })
|
||||
.ShouldBeTrue();
|
||||
q.AddPrioritized(new WaitingRequest { Reply = "2a", PriorityGroup = new PriorityGroup { Priority = 2 }, N = 1 })
|
||||
.ShouldBeTrue();
|
||||
q.AddPrioritized(new WaitingRequest { Reply = "1b", PriorityGroup = new PriorityGroup { Priority = 1 }, N = 1 })
|
||||
.ShouldBeTrue();
|
||||
q.AddPrioritized(new WaitingRequest { Reply = "2b", PriorityGroup = new PriorityGroup { Priority = 2 }, N = 1 })
|
||||
.ShouldBeTrue();
|
||||
q.AddPrioritized(new WaitingRequest { Reply = "1c", PriorityGroup = new PriorityGroup { Priority = 1 }, N = 1 })
|
||||
.ShouldBeTrue();
|
||||
q.AddPrioritized(new WaitingRequest { Reply = "3a", PriorityGroup = new PriorityGroup { Priority = 3 }, N = 1 })
|
||||
.ShouldBeTrue();
|
||||
q.AddPrioritized(new WaitingRequest { Reply = "2c", PriorityGroup = new PriorityGroup { Priority = 2 }, N = 1 })
|
||||
.ShouldBeTrue();
|
||||
|
||||
var expectedOrder = new[]
|
||||
{
|
||||
("1a", 1),
|
||||
("1b", 1),
|
||||
("1c", 1),
|
||||
("2a", 2),
|
||||
("2b", 2),
|
||||
("2c", 2),
|
||||
("3a", 3),
|
||||
};
|
||||
|
||||
q.Len.ShouldBe(expectedOrder.Length);
|
||||
foreach (var (reply, priority) in expectedOrder)
|
||||
{
|
||||
var current = q.Peek();
|
||||
current.ShouldNotBeNull();
|
||||
current!.Reply.ShouldBe(reply);
|
||||
current.PriorityGroup.ShouldNotBeNull();
|
||||
current.PriorityGroup!.Priority.ShouldBe(priority);
|
||||
q.RemoveCurrent();
|
||||
}
|
||||
|
||||
q.IsEmpty().ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact] // T:1365
|
||||
public void WaitQueuePopAndRequeue_ShouldSucceed()
|
||||
{
|
||||
var q = new WaitQueue(max: 100);
|
||||
q.AddPrioritized(new WaitingRequest { Reply = "1a", N = 2, PriorityGroup = new PriorityGroup { Priority = 1 } })
|
||||
.ShouldBeTrue();
|
||||
q.AddPrioritized(new WaitingRequest { Reply = "1b", N = 1, PriorityGroup = new PriorityGroup { Priority = 1 } })
|
||||
.ShouldBeTrue();
|
||||
q.AddPrioritized(new WaitingRequest { Reply = "2a", N = 3, PriorityGroup = new PriorityGroup { Priority = 2 } })
|
||||
.ShouldBeTrue();
|
||||
|
||||
var wr = q.PopAndRequeue();
|
||||
wr.ShouldNotBeNull();
|
||||
wr!.Reply.ShouldBe("1a");
|
||||
wr.N.ShouldBe(1);
|
||||
q.Len.ShouldBe(3);
|
||||
|
||||
wr = q.PopAndRequeue();
|
||||
wr.ShouldNotBeNull();
|
||||
wr!.Reply.ShouldBe("1b");
|
||||
wr.N.ShouldBe(0);
|
||||
q.Len.ShouldBe(2);
|
||||
|
||||
wr = q.PopAndRequeue();
|
||||
wr.ShouldNotBeNull();
|
||||
wr!.Reply.ShouldBe("1a");
|
||||
wr.N.ShouldBe(0);
|
||||
q.Len.ShouldBe(1);
|
||||
|
||||
q.Peek()!.Reply.ShouldBe("2a");
|
||||
q.Peek()!.N.ShouldBe(3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,28 @@ public sealed class WaitQueueTests
|
||||
q.Peek()!.Subject.ShouldBe("A");
|
||||
|
||||
q.Pop()!.Subject.ShouldBe("A");
|
||||
q.Pop()!.Subject.ShouldBe("B");
|
||||
q.Len.ShouldBe(1);
|
||||
|
||||
q.Pop()!.Subject.ShouldBe("B");
|
||||
q.Len.ShouldBe(0);
|
||||
q.IsFull(1).ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddPrioritized_AndCycle_ShouldPreserveStableOrder()
|
||||
{
|
||||
var q = new WaitQueue(max: 10);
|
||||
|
||||
q.AddPrioritized(new WaitingRequest { Reply = "2a", N = 1, PriorityGroup = new PriorityGroup { Priority = 2 } })
|
||||
.ShouldBeTrue();
|
||||
q.AddPrioritized(new WaitingRequest { Reply = "1a", N = 1, PriorityGroup = new PriorityGroup { Priority = 1 } })
|
||||
.ShouldBeTrue();
|
||||
q.AddPrioritized(new WaitingRequest { Reply = "1b", N = 1, PriorityGroup = new PriorityGroup { Priority = 1 } })
|
||||
.ShouldBeTrue();
|
||||
|
||||
q.Peek()!.Reply.ShouldBe("1a");
|
||||
q.Cycle();
|
||||
q.Peek()!.Reply.ShouldBe("1b");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user