From 31bc2d6717a8e1ceec04ec1a90ad351c88d27426 Mon Sep 17 00:00:00 2001 From: orician Date: Mon, 29 Sep 2025 00:17:18 +0800 Subject: [PATCH] feat: add NewServerFromConfig function for embedded server config processing This commit introduces NewServerFromConfig() function that automatically processes configuration files for embedded NATS servers, eliminating the need for manual LoadConfig() calls. Key changes: - Add NewServerFromConfig() function in server/server.go - Function automatically calls opts.ProcessConfigFile() when ConfigFile is set and configDigest is empty - Add comprehensive test coverage in server/opts_test.go: * TestNewServerFromConfigFunctionality: tests basic functionality and error handling * TestNewServerFromConfigVsLoadConfig: validates equivalence with LoadConfig approach The new function provides a cleaner API for embedded servers while maintaining full backward compatibility with existing LoadConfig workflows. Signed-off-by: orician --- server/opts_test.go | 73 +++++++++++++++++++++++++++++++++++++++++++++ server/server.go | 9 ++++++ 2 files changed, 82 insertions(+) diff --git a/server/opts_test.go b/server/opts_test.go index 4f47cbaaf0c..2f3077fb826 100644 --- a/server/opts_test.go +++ b/server/opts_test.go @@ -3921,3 +3921,76 @@ func TestOptionsProxyRequired(t *testing.T) { require_NoError(t, err) checkUsersAndNkeys(o.LeafNode.Users, false, nil) } + +// TestNewServerFromConfigFunctionality tests the NewServerFromConfig() function +// to ensure it properly processes config files and creates servers correctly. +func TestNewServerFromConfigFunctionality(t *testing.T) { + // Test 1: Error handling - invalid configuration + confFileName := createConfFile(t, []byte(` + max_payload = 3000000000 + `)) + + opts1 := &Options{ + ConfigFile: confFileName, + } + + // Should fail due to oversized max_payload (same as TestLargeMaxPayload) + if _, err := NewServerFromConfig(opts1); err == nil { + t.Fatalf("Expected an error from too large of a max_payload entry") + } + + // Test 2: Config validation error - max_pending > max_payload + confFileName = createConfFile(t, []byte(` + max_payload = 100000 + max_pending = 50000 + `)) + + opts2 := &Options{ + ConfigFile: confFileName, + } + + // This should trigger validation error (same as TestLargeMaxPayload) + server, err := NewServerFromConfig(opts2) + if err == nil || !strings.Contains(err.Error(), "cannot be higher") { + if server != nil { + server.Shutdown() + } + t.Fatalf("Expected validation error, got: %v", err) + } +} + +// TestNewServerFromConfigVsLoadConfig tests that NewServerFromConfig produces +// equivalent results to the traditional LoadConfig approach. +func TestNewServerFromConfigVsLoadConfig(t *testing.T) { + confFileName := createConfFile(t, []byte(` + port = 4224 + max_payload = 4194304 + max_connections = 200 + ping_interval = "30s" + `)) + + // Method 1: Using LoadConfig (traditional approach) + opts1 := LoadConfig(confFileName) + + // Method 2: Using NewServerFromConfig (new approach for embedded servers) + opts2 := &Options{ConfigFile: confFileName} + + // Test 1: Both should be able to create servers successfully + server1, err := NewServer(opts1) + if err != nil { + t.Fatalf("Failed to create server with LoadConfig options: %v", err) + } + server1.Shutdown() + + server2, err := NewServerFromConfig(opts2) + if err != nil { + t.Fatalf("Failed to create server with NewServerFromConfig: %v", err) + } + server2.Shutdown() + + // Test 2: Both methods should produce equivalent results - normalize test environment fields + // LoadConfig sets these fields for testing, so we need to match them for fair comparison + opts2.NoSigs, opts2.NoLog = true, opts2.LogFile == _EMPTY_ + + checkOptionsEqual(t, opts1, opts2) +} diff --git a/server/server.go b/server/server.go index 2971fbe8eed..5c88609e2e4 100644 --- a/server/server.go +++ b/server/server.go @@ -697,6 +697,15 @@ func New(opts *Options) *Server { return s } +func NewServerFromConfig(opts *Options) (*Server, error) { + if opts.ConfigFile != _EMPTY_ && opts.configDigest == "" { + if err := opts.ProcessConfigFile(opts.ConfigFile); err != nil { + return nil, err + } + } + return NewServer(opts) +} + // NewServer will setup a new server struct after parsing the options. // Could return an error if options can not be validated. // The provided Options type should not be re-used afterwards.