using System.Text; using Shouldly; using ZB.MOM.NatsNet.Server.Internal; using ZB.MOM.NatsNet.Server.Internal.DataStructures; namespace ZB.MOM.NatsNet.Server.Tests; public sealed class NatsServerJetStreamEventsTests { [Fact] public void PublishAdvisory_NullAccount_UsesSystemAccount() { var server = NewServer(new ServerOptions()); server.SetDefaultSystemAccount().ShouldBeNull(); var systemAccount = server.SystemAccount(); systemAccount.ShouldNotBeNull(); const string subject = "$JS.EVENT.ADVISORY.API"; AddInterest(systemAccount!, subject); Account? capturedAccount = null; var result = server.PublishAdvisory( acc: null, subject, new { Event = "ok" }, sendInternalAccountMessage: (account, _, _) => { capturedAccount = account; return null; }); result.ShouldBeTrue(); capturedAccount.ShouldBe(systemAccount); } [Fact] public void PublishAdvisory_NoInterest_ReturnsFalseWithoutSend() { var server = NewServer(new ServerOptions { NoSystemAccount = true }); var account = new Account { Name = "A" }; var sendCalls = 0; var result = server.PublishAdvisory( account, "$JS.EVENT.ADVISORY.API", new { Event = "no-interest" }, sendInternalAccountMessage: (_, _, _) => { sendCalls++; return null; }, hasGatewayInterest: (_, _) => false); result.ShouldBeFalse(); sendCalls.ShouldBe(0); } [Fact] public void PublishAdvisory_MarshalFailure_ReturnsFalse() { var server = NewServer(new ServerOptions { NoSystemAccount = true }); var account = new Account { Name = "A" }; AddInterest(account, "$JS.EVENT.ADVISORY.API"); var sendCalls = 0; var advisory = new CyclicAdvisory(); advisory.Self = advisory; var result = server.PublishAdvisory( account, "$JS.EVENT.ADVISORY.API", advisory, sendInternalAccountMessage: (_, _, _) => { sendCalls++; return null; }); result.ShouldBeFalse(); sendCalls.ShouldBe(0); } [Fact] public void PublishAdvisory_SendFailure_ReturnsFalse() { var server = NewServer(new ServerOptions { NoSystemAccount = true }); var account = new Account { Name = "A" }; AddInterest(account, "$JS.EVENT.ADVISORY.API"); var result = server.PublishAdvisory( account, "$JS.EVENT.ADVISORY.API", new { Event = "send-error" }, sendInternalAccountMessage: (_, _, _) => new InvalidOperationException("send failed")); result.ShouldBeFalse(); } [Fact] public void PublishAdvisory_SendSucceeds_ReturnsTrue() { var server = NewServer(new ServerOptions { NoSystemAccount = true }); var account = new Account { Name = "A" }; AddInterest(account, "$JS.EVENT.ADVISORY.API"); byte[]? payload = null; var result = server.PublishAdvisory( account, "$JS.EVENT.ADVISORY.API", new { Event = "sent" }, sendInternalAccountMessage: (_, _, bytes) => { payload = bytes; return null; }); result.ShouldBeTrue(); payload.ShouldNotBeNull(); Encoding.UTF8.GetString(payload!).ShouldContain("\"Event\":\"sent\""); } private static NatsServer NewServer(ServerOptions options) { var (server, err) = NatsServer.NewServer(options); err.ShouldBeNull(); server.ShouldNotBeNull(); return server!; } private static void AddInterest(Account account, string subject) { account.Sublist ??= SubscriptionIndex.NewSublistWithCache(); var err = account.Sublist.Insert(new Subscription { Subject = Encoding.ASCII.GetBytes(subject), }); err.ShouldBeNull(); } private sealed class CyclicAdvisory { public CyclicAdvisory? Self { get; set; } } }