using NATS.Server.Auth; using NATS.Server.Imports; namespace NATS.Server.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); } }