Implement deferred core utility parity APIs/tests and refresh tracking artifacts
This commit is contained in:
@@ -77,4 +77,16 @@ public sealed class AccessTimeServiceTests : IDisposable
|
||||
// Mirror: TestUnbalancedUnregister
|
||||
Should.Throw<InvalidOperationException>(() => AccessTimeService.Unregister());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Init_ShouldBeIdempotentAndNonThrowing()
|
||||
{
|
||||
Should.NotThrow(() => AccessTimeService.Init());
|
||||
var first = AccessTimeService.AccessTime();
|
||||
first.ShouldBeGreaterThan(0);
|
||||
|
||||
Should.NotThrow(() => AccessTimeService.Init());
|
||||
var second = AccessTimeService.AccessTime();
|
||||
second.ShouldBeGreaterThan(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,62 @@ namespace ZB.MOM.NatsNet.Server.Tests.Internal;
|
||||
/// </summary>
|
||||
public sealed class IpQueueTests
|
||||
{
|
||||
[Fact]
|
||||
public void IpqMaxRecycleSize_ShouldAffectQueueConfig()
|
||||
{
|
||||
var q = IpQueue<int>.NewIPQueue("opt-max-recycle", null, IpQueue<int>.IpqMaxRecycleSize(123));
|
||||
q.MaxRecycleSize.ShouldBe(123);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IpqSizeCalculation_AndLimitBySize_ShouldEnforceLimit()
|
||||
{
|
||||
var q = IpQueue<byte[]>.NewIPQueue(
|
||||
"opt-size-limit",
|
||||
null,
|
||||
IpQueue<byte[]>.IpqSizeCalculation(e => (ulong)e.Length),
|
||||
IpQueue<byte[]>.IpqLimitBySize(8));
|
||||
|
||||
var (_, err1) = q.Push(new byte[4]);
|
||||
err1.ShouldBeNull();
|
||||
|
||||
var (_, err2) = q.Push(new byte[4]);
|
||||
err2.ShouldBeNull();
|
||||
|
||||
var (_, err3) = q.Push(new byte[1]);
|
||||
err3.ShouldBeSameAs(IpQueueErrors.SizeLimitReached);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IpqLimitByLen_ShouldEnforceLengthLimit()
|
||||
{
|
||||
var q = IpQueue<int>.NewIPQueue("opt-len-limit", null, IpQueue<int>.IpqLimitByLen(2));
|
||||
|
||||
q.Push(1).error.ShouldBeNull();
|
||||
q.Push(2).error.ShouldBeNull();
|
||||
q.Push(3).error.ShouldBeSameAs(IpQueueErrors.LenLimitReached);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NewIPQueue_ShouldApplyOptionsAndRegister()
|
||||
{
|
||||
var registry = new ConcurrentDictionary<string, object>();
|
||||
var q = IpQueue<int>.NewIPQueue(
|
||||
"opt-factory",
|
||||
registry,
|
||||
IpQueue<int>.IpqMaxRecycleSize(55),
|
||||
IpQueue<int>.IpqLimitByLen(1));
|
||||
|
||||
q.MaxRecycleSize.ShouldBe(55);
|
||||
registry.TryGetValue("opt-factory", out var registered).ShouldBeTrue();
|
||||
registered.ShouldBeSameAs(q);
|
||||
|
||||
var (_, err1) = q.Push(1);
|
||||
err1.ShouldBeNull();
|
||||
var (_, err2) = q.Push(2);
|
||||
err2.ShouldBeSameAs(IpQueueErrors.LenLimitReached);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Basic_ShouldInitialiseCorrectly()
|
||||
{
|
||||
|
||||
@@ -22,6 +22,17 @@ namespace ZB.MOM.NatsNet.Server.Tests.Internal;
|
||||
/// </summary>
|
||||
public sealed class RateCounterTests
|
||||
{
|
||||
[Fact]
|
||||
public void NewRateCounter_ShouldCreateWithDefaultInterval()
|
||||
{
|
||||
var counter = RateCounter.NewRateCounter(2);
|
||||
counter.Interval.ShouldBe(TimeSpan.FromSeconds(1));
|
||||
|
||||
counter.Allow().ShouldBeTrue();
|
||||
counter.Allow().ShouldBeTrue();
|
||||
counter.Allow().ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RateCounter_ShouldAllowUpToLimitThenBlockAndReset()
|
||||
{
|
||||
|
||||
@@ -11,7 +11,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using Shouldly;
|
||||
using ZB.MOM.NatsNet.Server;
|
||||
using ZB.MOM.NatsNet.Server.Internal;
|
||||
|
||||
namespace ZB.MOM.NatsNet.Server.Tests.Internal;
|
||||
@@ -191,4 +194,86 @@ public sealed class ServerUtilitiesTests
|
||||
$"VersionAtLeast({version}, {major}, {minor}, {update})");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RefCountedUrlSet_Wrappers_ShouldTrackRefCounts()
|
||||
{
|
||||
var set = new RefCountedUrlSet();
|
||||
ServerUtilities.AddUrl(set, "nats://a:4222").ShouldBeTrue();
|
||||
ServerUtilities.AddUrl(set, "nats://a:4222").ShouldBeFalse();
|
||||
ServerUtilities.AddUrl(set, "nats://b:4222").ShouldBeTrue();
|
||||
|
||||
ServerUtilities.RemoveUrl(set, "nats://a:4222").ShouldBeFalse();
|
||||
ServerUtilities.RemoveUrl(set, "nats://a:4222").ShouldBeTrue();
|
||||
|
||||
var urls = ServerUtilities.GetAsStringSlice(set);
|
||||
urls.Length.ShouldBe(1);
|
||||
urls[0].ShouldBe("nats://b:4222");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task NatsDialTimeout_ShouldConnectWithinTimeout()
|
||||
{
|
||||
using var listener = new System.Net.Sockets.TcpListener(IPAddress.Loopback, 0);
|
||||
listener.Start();
|
||||
var port = ((IPEndPoint)listener.LocalEndpoint).Port;
|
||||
var acceptTask = listener.AcceptTcpClientAsync();
|
||||
|
||||
using var client = await ServerUtilities.NatsDialTimeout(
|
||||
"tcp",
|
||||
$"127.0.0.1:{port}",
|
||||
TimeSpan.FromSeconds(2));
|
||||
|
||||
client.Connected.ShouldBeTrue();
|
||||
using var accepted = await acceptTask;
|
||||
accepted.Connected.ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GenerateInfoJSON_ShouldEmitInfoLineWithCRLF()
|
||||
{
|
||||
var info = new ServerInfo
|
||||
{
|
||||
Id = "S1",
|
||||
Name = "n1",
|
||||
Host = "127.0.0.1",
|
||||
Port = 4222,
|
||||
Version = "2.0.0",
|
||||
Proto = 1,
|
||||
GoVersion = "go1.23",
|
||||
};
|
||||
|
||||
var bytes = ServerUtilities.GenerateInfoJSON(info);
|
||||
var line = System.Text.Encoding.UTF8.GetString(bytes);
|
||||
line.ShouldStartWith("INFO ");
|
||||
line.ShouldEndWith("\r\n");
|
||||
|
||||
var json = line["INFO ".Length..^2];
|
||||
var payload = JsonSerializer.Deserialize<ServerInfo>(json);
|
||||
payload.ShouldNotBeNull();
|
||||
payload!.Id.ShouldBe("S1");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ParallelTaskQueue_ShouldExecuteQueuedActions()
|
||||
{
|
||||
var writer = ServerUtilities.ParallelTaskQueue(maxParallelism: 2);
|
||||
var ran = 0;
|
||||
var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
||||
for (var i = 0; i < 4; i++)
|
||||
{
|
||||
var accepted = writer.TryWrite(() =>
|
||||
{
|
||||
if (Interlocked.Increment(ref ran) == 4)
|
||||
tcs.TrySetResult();
|
||||
});
|
||||
accepted.ShouldBeTrue();
|
||||
}
|
||||
|
||||
writer.TryComplete().ShouldBeTrue();
|
||||
var finished = await Task.WhenAny(tcs.Task, Task.Delay(TimeSpan.FromSeconds(2)));
|
||||
finished.ShouldBe(tcs.Task);
|
||||
ran.ShouldBe(4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,16 @@ public sealed class SignalHandlerTests : IDisposable
|
||||
SignalHandler.CommandToUnixSignal(ServerCommand.LameDuckMode).ShouldBe(UnixSignal.SigUsr2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CommandToSignal_ShouldMatchCommandToUnixSignal()
|
||||
{
|
||||
foreach (var command in Enum.GetValues<ServerCommand>())
|
||||
{
|
||||
SignalHandler.CommandToSignal(command)
|
||||
.ShouldBe(SignalHandler.CommandToUnixSignal(command));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact] // T:3155
|
||||
public void SetProcessName_ShouldNotThrow()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user