This is an automated email from the ASF dual-hosted git repository.

alexstocks pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git

commit 010af55de146b8195281970693d95cad730e6732
Author: Akashisang <[email protected]>
AuthorDate: Mon Dec 22 07:40:16 2025 +0800

    test: add unit test for server/server (#3129)
    
    * test: add unit test for server/server
---
 server/server_test.go | 481 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 481 insertions(+)

diff --git a/server/server_test.go b/server/server_test.go
new file mode 100644
index 000000000..57555e343
--- /dev/null
+++ b/server/server_test.go
@@ -0,0 +1,481 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+package server
+
+import (
+       "strconv"
+       "sync"
+       "testing"
+)
+
+import (
+       "github.com/stretchr/testify/assert"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common"
+       "dubbo.apache.org/dubbo-go/v3/global"
+)
+
+// Test NewServer creates a server successfully
+func TestNewServer(t *testing.T) {
+       srv, err := NewServer()
+       assert.NoError(t, err)
+       assert.NotNil(t, srv)
+
+       // Verify server is properly initialized by using public API
+       // Try to register and retrieve a service to verify internal maps work
+       svcOpts := defaultServiceOptions()
+       svcOpts.Id = "init-test-service"
+       srv.registerServiceOptions(svcOpts)
+
+       retrieved := srv.GetServiceOptions("init-test-service")
+       assert.NotNil(t, retrieved, "Server should have properly initialized 
service maps")
+}
+
+// Test NewServer with options
+func TestNewServerWithOptions(t *testing.T) {
+       appCfg := &global.ApplicationConfig{
+               Name: "test-app",
+       }
+       srv, err := NewServer(
+               SetServerApplication(appCfg),
+               WithServerGroup("test-group"),
+       )
+       assert.NoError(t, err)
+       assert.NotNil(t, srv)
+
+       // Verify configuration by registering a service and checking its 
options
+       handler := &mockServerRPCService{}
+       err = srv.Register(handler, nil)
+       assert.NoError(t, err)
+
+       svcOpts := srv.GetServiceOptions(handler.Reference())
+       assert.NotNil(t, svcOpts)
+       assert.Equal(t, "test-group", svcOpts.Service.Group)
+}
+
+// Test GetServiceOptions
+func TestGetServiceOptions(t *testing.T) {
+       srv, err := NewServer()
+       assert.NoError(t, err)
+
+       svcOpts := defaultServiceOptions()
+       svcOpts.Id = "test-service"
+       srv.registerServiceOptions(svcOpts)
+
+       retrieved := srv.GetServiceOptions("test-service")
+       assert.NotNil(t, retrieved)
+       assert.Equal(t, "test-service", retrieved.Id)
+}
+
+// Test GetServiceOptions returns nil for non-existent service
+func TestGetServiceOptionsNotFound(t *testing.T) {
+       srv, err := NewServer()
+       assert.NoError(t, err)
+
+       retrieved := srv.GetServiceOptions("non-existent")
+       assert.Nil(t, retrieved)
+}
+
+// Test GetServiceInfo
+func TestGetServiceInfo(t *testing.T) {
+       srv, err := NewServer()
+       assert.NoError(t, err)
+
+       svcOpts := defaultServiceOptions()
+       svcOpts.Id = "test-service"
+       svcOpts.info = &common.ServiceInfo{
+               InterfaceName: "com.example.TestService",
+       }
+       srv.registerServiceOptions(svcOpts)
+
+       info := srv.GetServiceInfo("test-service")
+       assert.NotNil(t, info)
+       assert.Equal(t, "com.example.TestService", info.InterfaceName)
+}
+
+// Test GetServiceInfo returns nil for non-existent service
+func TestGetServiceInfoNotFound(t *testing.T) {
+       srv, err := NewServer()
+       assert.NoError(t, err)
+
+       info := srv.GetServiceInfo("non-existent")
+       assert.Nil(t, info)
+}
+
+// Test GetRPCService
+func TestGetRPCService(t *testing.T) {
+       srv, err := NewServer()
+       assert.NoError(t, err)
+
+       svcOpts := defaultServiceOptions()
+       svcOpts.Id = "test-service"
+       mockService := &mockServerRPCService{}
+       svcOpts.rpcService = mockService
+       srv.registerServiceOptions(svcOpts)
+
+       rpcService := srv.GetRPCService("test-service")
+       assert.NotNil(t, rpcService)
+       assert.Equal(t, mockService, rpcService)
+}
+
+// Test GetRPCService returns nil for non-existent service
+func TestGetRPCServiceNotFound(t *testing.T) {
+       srv, err := NewServer()
+       assert.NoError(t, err)
+
+       rpcService := srv.GetRPCService("non-existent")
+       assert.Nil(t, rpcService)
+}
+
+// Test GetServiceOptionsByInterfaceName
+func TestGetServiceOptionsByInterfaceName(t *testing.T) {
+       srv, err := NewServer()
+       assert.NoError(t, err)
+
+       svcOpts := defaultServiceOptions()
+       svcOpts.Id = "test-service"
+       svcOpts.Service.Interface = "com.example.TestService"
+       srv.registerServiceOptions(svcOpts)
+
+       retrieved := 
srv.GetServiceOptionsByInterfaceName("com.example.TestService")
+       assert.NotNil(t, retrieved)
+       assert.Equal(t, "test-service", retrieved.Id)
+}
+
+// Test GetServiceOptionsByInterfaceName returns nil for non-existent interface
+func TestGetServiceOptionsByInterfaceNameNotFound(t *testing.T) {
+       srv, err := NewServer()
+       assert.NoError(t, err)
+
+       retrieved := 
srv.GetServiceOptionsByInterfaceName("non.existent.Service")
+       assert.Nil(t, retrieved)
+}
+
+// Test registerServiceOptions
+func TestRegisterServiceOptions(t *testing.T) {
+       srv, err := NewServer()
+       assert.NoError(t, err)
+
+       svcOpts := defaultServiceOptions()
+       svcOpts.Id = "test-service"
+       svcOpts.Service.Interface = "com.example.TestService"
+
+       srv.registerServiceOptions(svcOpts)
+
+       // Verify via public API methods
+       retrieved := srv.GetServiceOptions("test-service")
+       assert.NotNil(t, retrieved)
+       assert.Equal(t, svcOpts, retrieved)
+
+       retrievedByInterface := 
srv.GetServiceOptionsByInterfaceName("com.example.TestService")
+       assert.NotNil(t, retrievedByInterface)
+       assert.Equal(t, svcOpts, retrievedByInterface)
+}
+
+// Test registerServiceOptions with empty interface
+func TestRegisterServiceOptionsEmptyInterface(t *testing.T) {
+       srv, err := NewServer()
+       assert.NoError(t, err)
+
+       svcOpts := defaultServiceOptions()
+       svcOpts.Id = "test-service"
+       svcOpts.Service.Interface = ""
+
+       srv.registerServiceOptions(svcOpts)
+
+       // Should be retrievable by service ID but not by interface name
+       retrieved := srv.GetServiceOptions("test-service")
+       assert.NotNil(t, retrieved)
+       assert.Equal(t, svcOpts, retrieved)
+
+       // Empty interface should not be retrievable by interface name
+       retrievedByInterface := srv.GetServiceOptionsByInterfaceName("")
+       assert.Nil(t, retrievedByInterface)
+}
+
+// Test SetProviderServices
+func TestSetProviderServices(t *testing.T) {
+       // Lock and backup original state
+       internalProLock.Lock()
+       originalServices := internalProServices
+       internalProServices = make([]*InternalService, 0, 16)
+       internalProLock.Unlock()
+
+       // Register cleanup to restore original state
+       t.Cleanup(func() {
+               internalProLock.Lock()
+               defer internalProLock.Unlock()
+               internalProServices = originalServices
+       })
+
+       internalService := &InternalService{
+               Name:     "test-internal-service",
+               Priority: 0,
+               Init: func(options *ServiceOptions) (*ServiceDefinition, bool) {
+                       return &ServiceDefinition{
+                               Handler: &mockServerRPCService{},
+                               Info:    nil,
+                               Opts:    []ServiceOption{},
+                       }, true
+               },
+       }
+
+       // This function will acquire the lock internally
+       SetProviderServices(internalService)
+
+       // Access the global variable safely with lock
+       internalProLock.Lock()
+       defer internalProLock.Unlock()
+       assert.Len(t, internalProServices, 1)
+       assert.Equal(t, "test-internal-service", internalProServices[0].Name)
+}
+
+// Test SetProviderServices with empty name
+func TestSetProviderServicesEmptyName(t *testing.T) {
+       // Lock and backup original state
+       internalProLock.Lock()
+       originalServices := internalProServices
+       internalProServices = make([]*InternalService, 0, 16)
+
+       // Unlock before calling SetProviderServices (which needs the lock)
+       internalProLock.Unlock()
+
+       // Register cleanup to restore original state
+       t.Cleanup(func() {
+               internalProLock.Lock()
+               defer internalProLock.Unlock()
+               internalProServices = originalServices
+       })
+
+       internalService := &InternalService{
+               Name: "",
+       }
+
+       // This function will acquire the lock internally
+       SetProviderServices(internalService)
+
+       // Access the global variable safely with lock
+       internalProLock.Lock()
+       defer internalProLock.Unlock()
+       assert.Len(t, internalProServices, 0)
+}
+
+// Test enhanceServiceInfo with nil info
+func TestEnhanceServiceInfoNil(t *testing.T) {
+       info := enhanceServiceInfo(nil)
+       assert.Nil(t, info)
+}
+
+// Test enhanceServiceInfo with methods
+func TestEnhanceServiceInfo(t *testing.T) {
+       info := &common.ServiceInfo{
+               InterfaceName: "com.example.Service",
+               Methods: []common.MethodInfo{
+                       {
+                               Name: "sayHello",
+                       },
+               },
+       }
+
+       result := enhanceServiceInfo(info)
+       assert.NotNil(t, result)
+       // Should have doubled methods (original + case-swapped)
+       assert.Equal(t, 2, len(result.Methods))
+       assert.Equal(t, "sayHello", result.Methods[0].Name)
+       // The swapped version should have capitalized first letter
+       assert.Equal(t, "SayHello", result.Methods[1].Name)
+}
+
+// Test getMetadataPort with default protocol
+func TestGetMetadataPortWithDefaultProtocol(t *testing.T) {
+       opts := defaultServerOptions()
+       opts.Application.MetadataServicePort = ""
+       opts.Protocols = map[string]*global.ProtocolConfig{
+               "dubbo": {
+                       Port: "20880",
+               },
+       }
+
+       port := getMetadataPort(opts)
+       assert.Equal(t, 20880, port)
+}
+
+// Test getMetadataPort with explicit port
+func TestGetMetadataPortExplicit(t *testing.T) {
+       opts := defaultServerOptions()
+       opts.Application.MetadataServicePort = "30880"
+
+       port := getMetadataPort(opts)
+       assert.Equal(t, 30880, port)
+}
+
+// Test getMetadataPort with no port
+func TestGetMetadataPortNoPort(t *testing.T) {
+       opts := defaultServerOptions()
+       opts.Application.MetadataServicePort = ""
+       opts.Protocols = map[string]*global.ProtocolConfig{}
+
+       port := getMetadataPort(opts)
+       assert.Equal(t, 0, port)
+}
+
+// Test getMetadataPort with invalid port
+func TestGetMetadataPortInvalid(t *testing.T) {
+       opts := defaultServerOptions()
+       opts.Application.MetadataServicePort = "invalid"
+
+       port := getMetadataPort(opts)
+       assert.Equal(t, 0, port)
+}
+
+// mockServerRPCService is a mock implementation for testing server_test.go 
only
+type mockServerRPCService struct{}
+
+func (m *mockServerRPCService) Invoke(methodName string, params []any, results 
[]any) error {
+       return nil
+}
+
+func (m *mockServerRPCService) Reference() string {
+       return "com.example.MockService"
+}
+
+// Test concurrency: multiple goroutines registering services
+func TestConcurrentServiceRegistration(t *testing.T) {
+       srv, err := NewServer()
+       assert.NoError(t, err)
+
+       var wg sync.WaitGroup
+       for i := 0; i < 10; i++ {
+               wg.Add(1)
+               go func(idx int) {
+                       defer wg.Done()
+                       svcOpts := defaultServiceOptions()
+                       svcOpts.Id = "service-" + strconv.Itoa(idx)
+                       srv.registerServiceOptions(svcOpts)
+               }(i)
+       }
+
+       wg.Wait()
+
+       // Verify all services were registered using public API
+       for i := 0; i < 10; i++ {
+               svcID := "service-" + strconv.Itoa(i)
+               retrieved := srv.GetServiceOptions(svcID)
+               assert.NotNil(t, retrieved, "Service %s should be registered", 
svcID)
+               assert.Equal(t, svcID, retrieved.Id)
+       }
+}
+
+// Test Register with ServiceInfo
+func TestRegisterWithServiceInfo(t *testing.T) {
+       srv, err := NewServer()
+       assert.NoError(t, err)
+
+       handler := &mockServerRPCService{}
+       info := &common.ServiceInfo{
+               InterfaceName: "com.example.Service",
+               Methods: []common.MethodInfo{
+                       {Name: "Method1"},
+               },
+       }
+
+       err = srv.Register(handler, info)
+       assert.NoError(t, err)
+
+       // Service should be registered
+       svcOpts := srv.GetServiceOptions(handler.Reference())
+       assert.NotNil(t, svcOpts)
+}
+
+// Test RegisterService without ServiceInfo
+func TestRegisterService(t *testing.T) {
+       srv, err := NewServer()
+       assert.NoError(t, err)
+
+       handler := &mockServerRPCService{}
+       err = srv.RegisterService(handler)
+       assert.NoError(t, err)
+
+       // Service should be registered with handler reference name
+       svcOpts := srv.GetServiceOptions(handler.Reference())
+       assert.NotNil(t, svcOpts)
+}
+
+// Test Register with handler that has method config
+func TestRegisterWithMethodConfig(t *testing.T) {
+       srv, err := NewServer()
+       assert.NoError(t, err)
+
+       handler := &mockServerRPCService{}
+       info := &common.ServiceInfo{
+               InterfaceName: "com.example.TestService",
+       }
+
+       err = srv.Register(
+               handler,
+               info,
+               WithInterface("com.example.TestService"),
+               WithGroup("test-group"),
+               WithVersion("1.0.0"),
+       )
+       assert.NoError(t, err)
+
+       svcOpts := srv.GetServiceOptions(handler.Reference())
+       assert.NotNil(t, svcOpts)
+       assert.Equal(t, "test-group", svcOpts.Service.Group)
+       assert.Equal(t, "1.0.0", svcOpts.Service.Version)
+}
+
+// Test genSvcOpts with missing server config
+func TestGenSvcOptsWithMissingServerConfig(t *testing.T) {
+       srv := &Server{
+               cfg: nil,
+       }
+
+       handler := &mockServerRPCService{}
+       _, err := srv.genSvcOpts(handler, nil)
+       assert.Error(t, err)
+       assert.Contains(t, err.Error(), "has not been initialized")
+}
+
+// Test exportServices with empty service map
+func TestExportServicesEmpty(t *testing.T) {
+       srv, err := NewServer()
+       assert.NoError(t, err)
+
+       err = srv.exportServices()
+       assert.NoError(t, err)
+}
+
+// Test NewServer with custom group option
+func TestNewServerWithCustomGroup(t *testing.T) {
+       srv, err := NewServer(WithServerGroup("test"))
+       assert.NoError(t, err)
+       assert.NotNil(t, srv)
+
+       // Verify the group option by registering a service and checking its 
configuration
+       handler := &mockServerRPCService{}
+       err = srv.Register(handler, nil)
+       assert.NoError(t, err)
+
+       svcOpts := srv.GetServiceOptions(handler.Reference())
+       assert.NotNil(t, svcOpts)
+       assert.Equal(t, "test", svcOpts.Service.Group)
+}

Reply via email to