// Copyright 2012-2026 The NATS Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Mirrors Go test helpers: RunServer, GetFreePort, etc. from server/test_test.go. using System.Net; using System.Net.Sockets; using Xunit.Abstractions; using ZB.MOM.NatsNet.Server; namespace ZB.MOM.NatsNet.Server.IntegrationTests.Helpers; /// /// Server lifecycle helpers for integration tests. /// Mirrors Go patterns from server/test_test.go: RunServer, GetFreePort, etc. /// internal static class TestServerHelper { /// /// Returns true if a NatsServer can be instantiated with basic options. /// Used as a Skip guard — if the server can't boot, all integration tests skip gracefully. /// public static bool CanBoot() { try { var opts = new ServerOptions { Host = "127.0.0.1", Port = -1, NoLog = true, NoSigs = true, }; var (server, err) = NatsServer.NewServer(opts); if (err != null || server == null) return false; server.Shutdown(); return true; } catch { return false; } } /// /// Creates and starts a NatsServer with the given options. /// Returns the running server and the options used. /// Mirrors Go RunServer. /// public static (NatsServer Server, ServerOptions Options) RunServer(ServerOptions opts) { var (server, err) = NatsServer.NewServer(opts); if (err != null) throw new InvalidOperationException($"Failed to create server: {err.Message}", err); if (server == null) throw new InvalidOperationException("Failed to create server: NewServer returned null."); server.Start(); return (server, opts); } /// /// Creates and starts a NatsServer with JetStream enabled and a temp store directory. /// Mirrors Go RunServer with JetStream options. /// public static NatsServer RunBasicJetStreamServer(ITestOutputHelper? output = null) { var storeDir = CreateTempDir("js-store-"); var opts = new ServerOptions { Host = "127.0.0.1", Port = -1, NoLog = true, NoSigs = true, JetStream = true, StoreDir = storeDir, }; var (server, _) = RunServer(opts); return server; } /// /// Creates and starts a NatsServer using the options parsed from a config file path. /// The config file content is read and minimal parsing extracts key options. /// Returns the running server and the options. /// public static (NatsServer Server, ServerOptions Options) RunServerWithConfig(string configFile) { var opts = new ServerOptions { ConfigFile = configFile, NoLog = true, NoSigs = true, }; return RunServer(opts); } /// /// Finds a free TCP port on loopback. /// Mirrors Go GetFreePort. /// public static int GetFreePort() { var listener = new TcpListener(IPAddress.Loopback, 0); listener.Start(); var port = ((IPEndPoint)listener.LocalEndpoint).Port; listener.Stop(); return port; } /// /// Creates a uniquely named temp directory with the given prefix. /// The caller is responsible for deleting it when done. /// public static string CreateTempDir(string prefix = "nats-test-") { var path = Path.Combine(Path.GetTempPath(), prefix + Guid.NewGuid().ToString("N")[..8]); Directory.CreateDirectory(path); return path; } }