using System.Net; using System.Net.Sockets; using Microsoft.Extensions.Logging.Abstractions; using NATS.Server.Configuration; using NATS.Server.LeafNodes; namespace NATS.Server.LeafNodes.Tests.LeafNodes; public class LeafConnectionAndRemoteConfigParityBatch1Tests { [Fact] public async Task LeafConnection_role_helpers_reflect_connection_flags() { await using var connection = CreateConnection(); connection.IsSolicitedLeafNode().ShouldBeFalse(); connection.IsSpokeLeafNode().ShouldBeFalse(); connection.IsHubLeafNode().ShouldBeTrue(); connection.IsIsolatedLeafNode().ShouldBeFalse(); connection.IsSolicited = true; connection.IsSpoke = true; connection.Isolated = true; connection.IsSolicitedLeafNode().ShouldBeTrue(); connection.IsSpokeLeafNode().ShouldBeTrue(); connection.IsHubLeafNode().ShouldBeFalse(); connection.IsIsolatedLeafNode().ShouldBeTrue(); } [Fact] public void RemoteLeafOptions_pick_next_url_round_robins() { var remote = new RemoteLeafOptions { Urls = [ "nats://127.0.0.1:7422", "nats://127.0.0.1:7423", "nats://127.0.0.1:7424", ], }; remote.PickNextUrl().ShouldBe("nats://127.0.0.1:7422"); remote.GetCurrentUrl().ShouldBe("nats://127.0.0.1:7422"); remote.PickNextUrl().ShouldBe("nats://127.0.0.1:7423"); remote.PickNextUrl().ShouldBe("nats://127.0.0.1:7424"); remote.PickNextUrl().ShouldBe("nats://127.0.0.1:7422"); } [Fact] public void RemoteLeafOptions_pick_next_url_without_entries_throws() { var remote = new RemoteLeafOptions(); Should.Throw(() => remote.PickNextUrl()); } [Fact] public void RemoteLeafOptions_saves_tls_hostname_and_user_password_from_url() { var remote = new RemoteLeafOptions(); remote.SaveTlsHostname("nats://leaf.example.com:7422"); remote.TlsName.ShouldBe("leaf.example.com"); remote.SaveUserPassword("nats://demo:secret@leaf.example.com:7422"); remote.Username.ShouldBe("demo"); remote.Password.ShouldBe("secret"); } [Fact] public void RemoteLeafOptions_connect_delay_round_trips() { var remote = new RemoteLeafOptions(); remote.GetConnectDelay().ShouldBe(TimeSpan.Zero); remote.SetConnectDelay(TimeSpan.FromSeconds(30)); remote.GetConnectDelay().ShouldBe(TimeSpan.FromSeconds(30)); } [Fact] public void RemoteLeafNodeStillValid_checks_configured_and_disabled_remotes() { var manager = new LeafNodeManager( new LeafNodeOptions { Host = "127.0.0.1", Port = 0, Remotes = ["127.0.0.1:7422"], RemoteLeaves = [ new RemoteLeafOptions { Urls = ["nats://127.0.0.1:7423"], }, ], }, new ServerStats(), "S1", _ => { }, _ => { }, NullLogger.Instance); manager.RemoteLeafNodeStillValid("127.0.0.1:7422").ShouldBeTrue(); manager.RemoteLeafNodeStillValid("nats://127.0.0.1:7423").ShouldBeTrue(); manager.RemoteLeafNodeStillValid("127.0.0.1:7999").ShouldBeFalse(); manager.DisableLeafConnect("127.0.0.1:7422"); manager.RemoteLeafNodeStillValid("127.0.0.1:7422").ShouldBeFalse(); } [Fact] public void LeafNode_delay_constants_match_go_defaults() { LeafNodeManager.LeafNodeReconnectDelayAfterLoopDetected.ShouldBe(TimeSpan.FromSeconds(30)); LeafNodeManager.LeafNodeReconnectAfterPermViolation.ShouldBe(TimeSpan.FromSeconds(30)); LeafNodeManager.LeafNodeReconnectDelayAfterClusterNameSame.ShouldBe(TimeSpan.FromSeconds(30)); LeafNodeManager.LeafNodeWaitBeforeClose.ShouldBe(TimeSpan.FromSeconds(5)); } private static LeafConnection CreateConnection() { var listener = new TcpListener(IPAddress.Loopback, 0); listener.Start(); var endpoint = (IPEndPoint)listener.LocalEndpoint; var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); client.Connect(endpoint); var server = listener.AcceptSocket(); server.Dispose(); listener.Stop(); return new LeafConnection(client); } }