- Rename tests/NATS.Server.Tests -> tests/NATS.Server.Core.Tests - Update solution file, InternalsVisibleTo, and csproj references - Remove JETSTREAM_INTEGRATION_MATRIX and NATS.NKeys from csproj (moved to JetStream.Tests and Auth.Tests) - Update all namespaces from NATS.Server.Tests.* to NATS.Server.Core.Tests.* - Replace private GetFreePort/ReadUntilAsync helpers with TestUtilities calls - Fix stale namespace in Transport.Tests/NetworkingGoParityTests.cs
150 lines
5.1 KiB
C#
150 lines
5.1 KiB
C#
using NATS.Server.Auth;
|
|
using NATS.Server.Imports;
|
|
|
|
namespace NATS.Server.Core.Tests;
|
|
|
|
public class ResponseRoutingTests
|
|
{
|
|
[Fact]
|
|
public void GenerateReplyPrefix_creates_unique_prefix()
|
|
{
|
|
var prefix1 = ResponseRouter.GenerateReplyPrefix();
|
|
var prefix2 = ResponseRouter.GenerateReplyPrefix();
|
|
|
|
prefix1.ShouldStartWith("_R_.");
|
|
prefix2.ShouldStartWith("_R_.");
|
|
prefix1.ShouldNotBe(prefix2);
|
|
prefix1.Length.ShouldBeGreaterThan(4);
|
|
}
|
|
|
|
[Fact]
|
|
public void GenerateReplyPrefix_ends_with_dot()
|
|
{
|
|
var prefix = ResponseRouter.GenerateReplyPrefix();
|
|
|
|
prefix.ShouldEndWith(".");
|
|
// Format: "_R_." + 10 chars + "." = 15 chars
|
|
prefix.Length.ShouldBe(15);
|
|
}
|
|
|
|
[Fact]
|
|
public void Singleton_response_import_removed_after_delivery()
|
|
{
|
|
var exporter = new Account("exporter");
|
|
exporter.AddServiceExport("api.test", ServiceResponseType.Singleton, null);
|
|
|
|
var replyPrefix = ResponseRouter.GenerateReplyPrefix();
|
|
var responseSi = new ServiceImport
|
|
{
|
|
DestinationAccount = exporter,
|
|
From = replyPrefix + ">",
|
|
To = "_INBOX.original.reply",
|
|
IsResponse = true,
|
|
ResponseType = ServiceResponseType.Singleton,
|
|
};
|
|
exporter.Exports.Responses[replyPrefix] = responseSi;
|
|
|
|
exporter.Exports.Responses.ShouldContainKey(replyPrefix);
|
|
|
|
// Simulate singleton delivery cleanup
|
|
ResponseRouter.CleanupResponse(exporter, replyPrefix, responseSi);
|
|
|
|
exporter.Exports.Responses.ShouldNotContainKey(replyPrefix);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateResponseImport_registers_in_exporter_responses()
|
|
{
|
|
var exporter = new Account("exporter");
|
|
var importer = new Account("importer");
|
|
exporter.AddServiceExport("api.test", ServiceResponseType.Singleton, null);
|
|
|
|
var originalSi = new ServiceImport
|
|
{
|
|
DestinationAccount = exporter,
|
|
From = "api.test",
|
|
To = "api.test",
|
|
Export = exporter.Exports.Services["api.test"],
|
|
ResponseType = ServiceResponseType.Singleton,
|
|
};
|
|
|
|
var responseSi = ResponseRouter.CreateResponseImport(exporter, originalSi, "_INBOX.abc123");
|
|
|
|
responseSi.IsResponse.ShouldBeTrue();
|
|
responseSi.ResponseType.ShouldBe(ServiceResponseType.Singleton);
|
|
responseSi.To.ShouldBe("_INBOX.abc123");
|
|
responseSi.DestinationAccount.ShouldBe(exporter);
|
|
responseSi.From.ShouldEndWith(">");
|
|
responseSi.Export.ShouldBe(originalSi.Export);
|
|
|
|
// Should be registered in the exporter's response map
|
|
exporter.Exports.Responses.Count.ShouldBe(1);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateResponseImport_preserves_streamed_response_type()
|
|
{
|
|
var exporter = new Account("exporter");
|
|
exporter.AddServiceExport("api.stream", ServiceResponseType.Streamed, null);
|
|
|
|
var originalSi = new ServiceImport
|
|
{
|
|
DestinationAccount = exporter,
|
|
From = "api.stream",
|
|
To = "api.stream",
|
|
Export = exporter.Exports.Services["api.stream"],
|
|
ResponseType = ServiceResponseType.Streamed,
|
|
};
|
|
|
|
var responseSi = ResponseRouter.CreateResponseImport(exporter, originalSi, "_INBOX.xyz789");
|
|
|
|
responseSi.ResponseType.ShouldBe(ServiceResponseType.Streamed);
|
|
}
|
|
|
|
[Fact]
|
|
public void Multiple_response_imports_each_get_unique_prefix()
|
|
{
|
|
var exporter = new Account("exporter");
|
|
exporter.AddServiceExport("api.test", ServiceResponseType.Singleton, null);
|
|
|
|
var originalSi = new ServiceImport
|
|
{
|
|
DestinationAccount = exporter,
|
|
From = "api.test",
|
|
To = "api.test",
|
|
Export = exporter.Exports.Services["api.test"],
|
|
ResponseType = ServiceResponseType.Singleton,
|
|
};
|
|
|
|
var resp1 = ResponseRouter.CreateResponseImport(exporter, originalSi, "_INBOX.reply1");
|
|
var resp2 = ResponseRouter.CreateResponseImport(exporter, originalSi, "_INBOX.reply2");
|
|
|
|
exporter.Exports.Responses.Count.ShouldBe(2);
|
|
resp1.To.ShouldBe("_INBOX.reply1");
|
|
resp2.To.ShouldBe("_INBOX.reply2");
|
|
resp1.From.ShouldNotBe(resp2.From);
|
|
}
|
|
|
|
[Fact]
|
|
public void LatencyTracker_should_sample_respects_percentage()
|
|
{
|
|
var latency = new ServiceLatency { SamplingPercentage = 0, Subject = "latency.test" };
|
|
LatencyTracker.ShouldSample(latency).ShouldBeFalse();
|
|
|
|
var latency100 = new ServiceLatency { SamplingPercentage = 100, Subject = "latency.test" };
|
|
LatencyTracker.ShouldSample(latency100).ShouldBeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void LatencyTracker_builds_latency_message()
|
|
{
|
|
var msg = LatencyTracker.BuildLatencyMsg("requester", "responder",
|
|
TimeSpan.FromMilliseconds(5), TimeSpan.FromMilliseconds(10));
|
|
|
|
msg.Requestor.ShouldBe("requester");
|
|
msg.Responder.ShouldBe("responder");
|
|
msg.ServiceLatencyNanos.ShouldBeGreaterThan(0);
|
|
msg.TotalLatencyNanos.ShouldBeGreaterThan(0);
|
|
}
|
|
}
|