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

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


The following commit(s) were added to refs/heads/develop by this push:
     new 6d9679bdd test: add unit test for server/action.go server/compat.go 
(#3132)
6d9679bdd is described below

commit 6d9679bdd1b2bcce6a07ed129ad37320d7d86a79
Author: Akashisang <[email protected]>
AuthorDate: Mon Dec 22 07:42:42 2025 +0800

    test: add unit test for server/action.go server/compat.go (#3132)
    
    * test: add unit test for server/
---
 server/action_test.go | 675 ++++++++++++++++++++++++++++++++++++++++++++++++++
 server/compat_test.go | 324 ++++++++++++++++++++++++
 2 files changed, 999 insertions(+)

diff --git a/server/action_test.go b/server/action_test.go
new file mode 100644
index 000000000..17c29f9e6
--- /dev/null
+++ b/server/action_test.go
@@ -0,0 +1,675 @@
+/*
+ * 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 (
+       "testing"
+)
+
+import (
+       "github.com/stretchr/testify/assert"
+
+       "go.uber.org/atomic"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common"
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+       "dubbo.apache.org/dubbo-go/v3/config"
+       "dubbo.apache.org/dubbo-go/v3/global"
+       "dubbo.apache.org/dubbo-go/v3/protocol/base"
+)
+
+// Test Prefix method
+func TestPrefix(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               Id: "com.example.TestService",
+       }
+
+       prefix := svcOpts.Prefix()
+       assert.Equal(t, "dubbo.service.com.example.TestService", prefix)
+}
+
+// Test InitExported
+func TestInitExported(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               exported: atomic.NewBool(true),
+       }
+
+       svcOpts.InitExported()
+       assert.False(t, svcOpts.exported.Load())
+}
+
+// Test IsExport returns false initially
+func TestIsExportFalse(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               exported: atomic.NewBool(false),
+       }
+
+       assert.False(t, svcOpts.IsExport())
+}
+
+// Test IsExport returns true when exported
+func TestIsExportTrue(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               exported: atomic.NewBool(true),
+       }
+
+       assert.True(t, svcOpts.IsExport())
+}
+
+// Test check with valid TpsLimiter
+func TestCheckValidTpsLimiter(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               Service: &global.ServiceConfig{
+                       Interface:  "com.example.Service",
+                       TpsLimiter: "",
+               },
+       }
+
+       err := svcOpts.check()
+       assert.NoError(t, err)
+}
+
+// Test check with valid TpsLimitRate
+func TestCheckValidTpsLimitRate(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               Service: &global.ServiceConfig{
+                       Interface:    "com.example.Service",
+                       TpsLimitRate: "1000",
+               },
+       }
+
+       err := svcOpts.check()
+       assert.NoError(t, err)
+}
+
+// Test check with invalid TpsLimitRate
+func TestCheckInvalidTpsLimitRate(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               Service: &global.ServiceConfig{
+                       Interface:    "com.example.Service",
+                       TpsLimitRate: "invalid",
+               },
+       }
+
+       err := svcOpts.check()
+       assert.Error(t, err)
+}
+
+// Test check with negative TpsLimitRate
+func TestCheckNegativeTpsLimitRate(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               Service: &global.ServiceConfig{
+                       Interface:    "com.example.Service",
+                       TpsLimitRate: "-1",
+               },
+       }
+
+       err := svcOpts.check()
+       assert.Error(t, err)
+}
+
+// Test check with valid TpsLimitInterval
+func TestCheckValidTpsLimitInterval(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               Service: &global.ServiceConfig{
+                       Interface:        "com.example.Service",
+                       TpsLimitInterval: "1000",
+               },
+       }
+
+       err := svcOpts.check()
+       assert.NoError(t, err)
+}
+
+// Test check with invalid TpsLimitInterval
+func TestCheckInvalidTpsLimitInterval(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               Service: &global.ServiceConfig{
+                       Interface:        "com.example.Service",
+                       TpsLimitInterval: "invalid",
+               },
+       }
+
+       err := svcOpts.check()
+       assert.Error(t, err)
+}
+
+// Test check with negative TpsLimitInterval
+func TestCheckNegativeTpsLimitInterval(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               Service: &global.ServiceConfig{
+                       Interface:        "com.example.Service",
+                       TpsLimitInterval: "-1",
+               },
+       }
+
+       err := svcOpts.check()
+       assert.Error(t, err)
+}
+
+// Test Implement
+func TestImplement(t *testing.T) {
+       svcOpts := &ServiceOptions{}
+       mockService := &mockRPCService{}
+
+       svcOpts.Implement(mockService)
+
+       assert.Equal(t, mockService, svcOpts.rpcService)
+}
+
+// Test Unexport when not exported
+func TestUnexportNotExported(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               unexported: atomic.NewBool(false),
+               exported:   atomic.NewBool(false),
+               exporters:  []base.Exporter{},
+       }
+
+       svcOpts.Unexport()
+       assert.False(t, svcOpts.exported.Load())
+       assert.False(t, svcOpts.unexported.Load())
+}
+
+// Test Unexport when already unexported
+func TestUnexportAlreadyUnexported(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               unexported: atomic.NewBool(true),
+               exported:   atomic.NewBool(false),
+               exporters:  []base.Exporter{},
+       }
+
+       svcOpts.Unexport()
+       assert.True(t, svcOpts.unexported.Load())
+}
+
+// Test removeDuplicateElement
+func TestRemoveDuplicateElement(t *testing.T) {
+       items := []string{"a", "b", "a", "c", "b", ""}
+       result := removeDuplicateElement(items)
+
+       assert.Len(t, result, 3)
+       assert.Contains(t, result, "a")
+       assert.Contains(t, result, "b")
+       assert.Contains(t, result, "c")
+}
+
+// Test removeDuplicateElement with empty slice
+func TestRemoveDuplicateElementEmpty(t *testing.T) {
+       items := []string{}
+       result := removeDuplicateElement(items)
+
+       assert.Len(t, result, 0)
+}
+
+// Test removeDuplicateElement with only empty strings
+func TestRemoveDuplicateElementOnlyEmpty(t *testing.T) {
+       items := []string{"", "", ""}
+       result := removeDuplicateElement(items)
+
+       assert.Len(t, result, 0)
+}
+
+// Test removeDuplicateElement with mixed content
+func TestRemoveDuplicateElementMixed(t *testing.T) {
+       items := []string{"reg1", "reg2", "reg1", "", "reg3", ""}
+       result := removeDuplicateElement(items)
+
+       assert.Len(t, result, 3)
+       assert.Contains(t, result, "reg1")
+       assert.Contains(t, result, "reg2")
+       assert.Contains(t, result, "reg3")
+}
+
+// Test getRegistryIds
+func TestGetRegistryIds(t *testing.T) {
+       registries := map[string]*global.RegistryConfig{
+               "reg1": {Protocol: "zookeeper"},
+               "reg2": {Protocol: "nacos"},
+               "reg3": {Protocol: "etcd"},
+       }
+
+       ids := getRegistryIds(registries)
+
+       assert.Len(t, ids, 3)
+       assert.Contains(t, ids, "reg1")
+       assert.Contains(t, ids, "reg2")
+       assert.Contains(t, ids, "reg3")
+}
+
+// Test getRegistryIds with empty map
+func TestGetRegistryIdsEmpty(t *testing.T) {
+       registries := map[string]*global.RegistryConfig{}
+
+       ids := getRegistryIds(registries)
+
+       assert.Len(t, ids, 0)
+}
+
+// Test GetExportedUrls when not exported
+func TestGetExportedUrlsNotExported(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               exported:  atomic.NewBool(false),
+               exporters: []base.Exporter{},
+       }
+
+       urls := svcOpts.GetExportedUrls()
+       assert.Nil(t, urls)
+}
+
+// Test GetExportedUrls when exported with no exporters
+func TestGetExportedUrlsExportedEmpty(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               exported:  atomic.NewBool(true),
+               exporters: []base.Exporter{},
+       }
+
+       urls := svcOpts.GetExportedUrls()
+       assert.Len(t, urls, 0)
+}
+
+// Test getUrlMap basic functionality
+func TestGetUrlMapBasic(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               Service: &global.ServiceConfig{
+                       Interface:     "com.example.Service",
+                       Cluster:       constant.ClusterKeyFailover,
+                       Loadbalance:   constant.LoadBalanceKeyRoundRobin,
+                       Warmup:        "60",
+                       Retries:       "3",
+                       Serialization: constant.JSONSerialization,
+                       Filter:        "",
+                       Params:        map[string]string{},
+                       NotRegister:   false,
+                       Tag:           "v1",
+                       Group:         "test-group",
+                       Version:       "1.0.0",
+               },
+               Provider: &global.ProviderConfig{},
+               applicationCompat: &config.ApplicationConfig{
+                       Name:         "test-app",
+                       Organization: "test-org",
+                       Module:       "test-module",
+                       Owner:        "test-owner",
+                       Environment:  "test-env",
+                       Version:      "1.0.0",
+               },
+               srvOpts: &ServerOptions{
+                       Metrics: &global.MetricsConfig{Enable: nil},
+                       Otel: &global.OtelConfig{
+                               TracingConfig: &global.OtelTraceConfig{Enable: 
nil},
+                       },
+               },
+       }
+
+       urlMap := svcOpts.getUrlMap()
+       assert.NotNil(t, urlMap)
+       assert.Equal(t, "com.example.Service", 
urlMap.Get(constant.InterfaceKey))
+       assert.Equal(t, constant.ClusterKeyFailover, 
urlMap.Get(constant.ClusterKey))
+       assert.Equal(t, constant.LoadBalanceKeyRoundRobin, 
urlMap.Get(constant.LoadbalanceKey))
+       assert.Equal(t, "60", urlMap.Get(constant.WarmupKey))
+       assert.Equal(t, "3", urlMap.Get(constant.RetriesKey))
+       assert.Equal(t, constant.JSONSerialization, 
urlMap.Get(constant.SerializationKey))
+}
+
+// Test getUrlMap with custom params
+func TestGetUrlMapWithParams(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               Service: &global.ServiceConfig{
+                       Interface: "com.example.Service",
+                       Params: map[string]string{
+                               "customKey": "customValue",
+                       },
+                       Cluster:       constant.ClusterKeyFailover,
+                       Loadbalance:   constant.LoadBalanceKeyRoundRobin,
+                       Warmup:        "60",
+                       Retries:       "3",
+                       Serialization: constant.JSONSerialization,
+               },
+               Provider: &global.ProviderConfig{},
+               applicationCompat: &config.ApplicationConfig{
+                       Name:         "test-app",
+                       Organization: "test-org",
+               },
+               srvOpts: &ServerOptions{
+                       Metrics: &global.MetricsConfig{},
+                       Otel: &global.OtelConfig{
+                               TracingConfig: &global.OtelTraceConfig{},
+                       },
+               },
+       }
+
+       urlMap := svcOpts.getUrlMap()
+       assert.NotNil(t, urlMap)
+       assert.Equal(t, "customValue", urlMap.Get("customKey"))
+}
+
+// Test getUrlMap with group and version
+func TestGetUrlMapWithGroupAndVersion(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               Service: &global.ServiceConfig{
+                       Interface:     "com.example.Service",
+                       Group:         "test-group",
+                       Version:       "1.0.0",
+                       Cluster:       constant.ClusterKeyFailover,
+                       Loadbalance:   constant.LoadBalanceKeyRoundRobin,
+                       Warmup:        "60",
+                       Retries:       "3",
+                       Serialization: constant.JSONSerialization,
+                       Params:        map[string]string{},
+               },
+               Provider: &global.ProviderConfig{},
+               applicationCompat: &config.ApplicationConfig{
+                       Name: "test-app",
+               },
+               srvOpts: &ServerOptions{
+                       Metrics: &global.MetricsConfig{},
+                       Otel: &global.OtelConfig{
+                               TracingConfig: &global.OtelTraceConfig{},
+                       },
+               },
+       }
+
+       urlMap := svcOpts.getUrlMap()
+       assert.Equal(t, "test-group", urlMap.Get(constant.GroupKey))
+       assert.Equal(t, "1.0.0", urlMap.Get(constant.VersionKey))
+}
+
+// Test getUrlMap with methods
+func TestGetUrlMapWithMethods(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               Service: &global.ServiceConfig{
+                       Interface:     "com.example.Service",
+                       Cluster:       constant.ClusterKeyFailover,
+                       Loadbalance:   constant.LoadBalanceKeyRoundRobin,
+                       Warmup:        "60",
+                       Retries:       "3",
+                       Serialization: constant.JSONSerialization,
+                       Params:        map[string]string{},
+                       Methods: []*global.MethodConfig{
+                               {
+                                       Name:        "testMethod",
+                                       LoadBalance: "random",
+                                       Retries:     "5",
+                                       Weight:      200,
+                               },
+                       },
+               },
+               Provider: &global.ProviderConfig{},
+               applicationCompat: &config.ApplicationConfig{
+                       Name: "test-app",
+               },
+               srvOpts: &ServerOptions{
+                       Metrics: &global.MetricsConfig{},
+                       Otel: &global.OtelConfig{
+                               TracingConfig: &global.OtelTraceConfig{},
+                       },
+               },
+       }
+
+       urlMap := svcOpts.getUrlMap()
+       assert.Equal(t, "random", 
urlMap.Get("methods.testMethod."+constant.LoadbalanceKey))
+       assert.Equal(t, "5", 
urlMap.Get("methods.testMethod."+constant.RetriesKey))
+       assert.Equal(t, "200", 
urlMap.Get("methods.testMethod."+constant.WeightKey))
+}
+
+// Test loadProtocol with matching IDs
+func TestLoadProtocol(t *testing.T) {
+       protocols := map[string]*global.ProtocolConfig{
+               "dubbo": {
+                       Name: "dubbo",
+                       Port: "20880",
+               },
+               "triple": {
+                       Name: "triple",
+                       Port: "50051",
+               },
+       }
+
+       protocolIDs := []string{"dubbo", "triple"}
+       result := loadProtocol(protocolIDs, protocols)
+
+       assert.Len(t, result, 2)
+}
+
+// Test loadProtocol with partial matching
+func TestLoadProtocolPartialMatch(t *testing.T) {
+       protocols := map[string]*global.ProtocolConfig{
+               "dubbo": {
+                       Name: "dubbo",
+                       Port: "20880",
+               },
+               "triple": {
+                       Name: "triple",
+                       Port: "50051",
+               },
+       }
+
+       protocolIDs := []string{"dubbo"}
+       result := loadProtocol(protocolIDs, protocols)
+
+       assert.Len(t, result, 1)
+       assert.Equal(t, "dubbo", result[0].Name)
+}
+
+// Test loadProtocol with no matching IDs
+func TestLoadProtocolNoMatch(t *testing.T) {
+       protocols := map[string]*global.ProtocolConfig{
+               "dubbo": {
+                       Name: "dubbo",
+                       Port: "20880",
+               },
+       }
+
+       protocolIDs := []string{"non-existent"}
+       result := loadProtocol(protocolIDs, protocols)
+
+       assert.Len(t, result, 0)
+}
+
+// Test setRegistrySubURL
+func TestSetRegistrySubURL(t *testing.T) {
+       ivkURL, _ := 
common.NewURL("dubbo://localhost:20880/com.example.Service")
+       ivkURL.AddParam(constant.RegistryKey, "zookeeper")
+       ivkURL.AddParam(constant.RegistryTypeKey, "service_discovery")
+
+       regURL, _ := common.NewURL("registry://zookeeper:2181")
+       regURL.AddParam(constant.RegistryKey, "zookeeper")
+       regURL.AddParam(constant.RegistryTypeKey, "service_discovery")
+
+       setRegistrySubURL(ivkURL, regURL)
+
+       assert.Equal(t, "zookeeper", ivkURL.GetParam(constant.RegistryKey, ""))
+       assert.Equal(t, "service_discovery", 
ivkURL.GetParam(constant.RegistryTypeKey, ""))
+       assert.NotNil(t, regURL.SubURL)
+}
+
+// Test Unexport when exported
+func TestUnexportWhenExported(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               unexported: atomic.NewBool(false),
+               exported:   atomic.NewBool(true),
+               exporters:  []base.Exporter{},
+       }
+
+       svcOpts.Unexport()
+       assert.False(t, svcOpts.exported.Load())
+       assert.True(t, svcOpts.unexported.Load())
+}
+
+// Test check with multiple validation errors
+func TestCheckMultipleErrors(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               Service: &global.ServiceConfig{
+                       Interface:        "com.example.Service",
+                       TpsLimitRate:     "invalid",
+                       TpsLimitInterval: "also-invalid",
+               },
+       }
+
+       err := svcOpts.check()
+       assert.Error(t, err)
+}
+
+// Test getUrlMap with TPS limit config
+func TestGetUrlMapWithTpsLimit(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               Service: &global.ServiceConfig{
+                       Interface:               "com.example.Service",
+                       TpsLimiter:              "default",
+                       TpsLimitRate:            "1000",
+                       TpsLimitStrategy:        "adaptive",
+                       TpsLimitRejectedHandler: "abort",
+                       TpsLimitInterval:        "100",
+                       Cluster:                 constant.ClusterKeyFailover,
+                       Loadbalance:             
constant.LoadBalanceKeyRoundRobin,
+                       Warmup:                  "60",
+                       Retries:                 "3",
+                       Serialization:           constant.JSONSerialization,
+                       Params:                  map[string]string{},
+               },
+               Provider: &global.ProviderConfig{},
+               applicationCompat: &config.ApplicationConfig{
+                       Name: "test-app",
+               },
+               srvOpts: &ServerOptions{
+                       Metrics: &global.MetricsConfig{},
+                       Otel: &global.OtelConfig{
+                               TracingConfig: &global.OtelTraceConfig{},
+                       },
+               },
+       }
+
+       urlMap := svcOpts.getUrlMap()
+       assert.Equal(t, "default", urlMap.Get(constant.TPSLimiterKey))
+       assert.Equal(t, "1000", urlMap.Get(constant.TPSLimitRateKey))
+       assert.Equal(t, "adaptive", urlMap.Get(constant.TPSLimitStrategyKey))
+       assert.Equal(t, "abort", 
urlMap.Get(constant.TPSRejectedExecutionHandlerKey))
+}
+
+// Test getUrlMap with execute limit config
+func TestGetUrlMapWithExecuteLimit(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               Service: &global.ServiceConfig{
+                       Interface:                   "com.example.Service",
+                       ExecuteLimit:                "200",
+                       ExecuteLimitRejectedHandler: "abort",
+                       Cluster:                     
constant.ClusterKeyFailover,
+                       Loadbalance:                 
constant.LoadBalanceKeyRoundRobin,
+                       Warmup:                      "60",
+                       Retries:                     "3",
+                       Serialization:               constant.JSONSerialization,
+                       Params:                      map[string]string{},
+               },
+               Provider: &global.ProviderConfig{},
+               applicationCompat: &config.ApplicationConfig{
+                       Name: "test-app",
+               },
+               srvOpts: &ServerOptions{
+                       Metrics: &global.MetricsConfig{},
+                       Otel: &global.OtelConfig{
+                               TracingConfig: &global.OtelTraceConfig{},
+                       },
+               },
+       }
+
+       urlMap := svcOpts.getUrlMap()
+       assert.Equal(t, "200", urlMap.Get(constant.ExecuteLimitKey))
+       assert.Equal(t, "abort", 
urlMap.Get(constant.ExecuteRejectedExecutionHandlerKey))
+}
+
+// Test getUrlMap with auth and param sign
+func TestGetUrlMapWithAuthAndParamSign(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               Service: &global.ServiceConfig{
+                       Interface:     "com.example.Service",
+                       Auth:          "default",
+                       ParamSign:     "md5",
+                       Cluster:       constant.ClusterKeyFailover,
+                       Loadbalance:   constant.LoadBalanceKeyRoundRobin,
+                       Warmup:        "60",
+                       Retries:       "3",
+                       Serialization: constant.JSONSerialization,
+                       Params:        map[string]string{},
+               },
+               Provider: &global.ProviderConfig{},
+               applicationCompat: &config.ApplicationConfig{
+                       Name: "test-app",
+               },
+               srvOpts: &ServerOptions{
+                       Metrics: &global.MetricsConfig{},
+                       Otel: &global.OtelConfig{
+                               TracingConfig: &global.OtelTraceConfig{},
+                       },
+               },
+       }
+
+       urlMap := svcOpts.getUrlMap()
+       assert.Equal(t, "default", urlMap.Get(constant.ServiceAuthKey))
+       assert.Equal(t, "md5", urlMap.Get(constant.ParameterSignatureEnableKey))
+}
+
+// Test getUrlMap with access log
+func TestGetUrlMapWithAccessLog(t *testing.T) {
+       svcOpts := &ServiceOptions{
+               Service: &global.ServiceConfig{
+                       Interface:     "com.example.Service",
+                       AccessLog:     "/var/log/access.log",
+                       Cluster:       constant.ClusterKeyFailover,
+                       Loadbalance:   constant.LoadBalanceKeyRoundRobin,
+                       Warmup:        "60",
+                       Retries:       "3",
+                       Serialization: constant.JSONSerialization,
+                       Params:        map[string]string{},
+               },
+               Provider: &global.ProviderConfig{},
+               applicationCompat: &config.ApplicationConfig{
+                       Name: "test-app",
+               },
+               srvOpts: &ServerOptions{
+                       Metrics: &global.MetricsConfig{},
+                       Otel: &global.OtelConfig{
+                               TracingConfig: &global.OtelTraceConfig{},
+                       },
+               },
+       }
+
+       urlMap := svcOpts.getUrlMap()
+       assert.Equal(t, "/var/log/access.log", 
urlMap.Get(constant.AccessLogFilterKey))
+}
+
+// Test postProcessConfig
+func TestPostProcessConfig(t *testing.T) {
+       svcOpts := &ServiceOptions{}
+       url, _ := common.NewURL("dubbo://localhost:20880/test")
+
+       svcOpts.postProcessConfig(url)
+       assert.NotNil(t, url)
+}
+
+// Mock RPCService for testing
+type mockRPCService struct{}
+
+func (m *mockRPCService) Invoke(methodName string, params []any, results 
[]any) error {
+       return nil
+}
+
+func (m *mockRPCService) Reference() string {
+       return "com.example.MockService"
+}
diff --git a/server/compat_test.go b/server/compat_test.go
new file mode 100644
index 000000000..f58fe6f68
--- /dev/null
+++ b/server/compat_test.go
@@ -0,0 +1,324 @@
+/*
+ * 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 (
+       "testing"
+)
+
+import (
+       "github.com/stretchr/testify/assert"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/config"
+       "dubbo.apache.org/dubbo-go/v3/global"
+)
+
+// Test compatApplicationConfig with all fields
+func TestCompatApplicationConfigAll(t *testing.T) {
+       appCfg := &global.ApplicationConfig{
+               Organization:            "test-org",
+               Name:                    "test-app",
+               Module:                  "test-module",
+               Group:                   "test-group",
+               Version:                 "1.0.0",
+               Owner:                   "test-owner",
+               Environment:             "test-env",
+               MetadataType:            "remote",
+               Tag:                     "v1",
+               MetadataServicePort:     "30880",
+               MetadataServiceProtocol: "triple",
+       }
+
+       result := compatApplicationConfig(appCfg)
+
+       assert.NotNil(t, result)
+       assert.Equal(t, "test-org", result.Organization)
+       assert.Equal(t, "test-app", result.Name)
+       assert.Equal(t, "test-module", result.Module)
+       assert.Equal(t, "test-group", result.Group)
+       assert.Equal(t, "1.0.0", result.Version)
+       assert.Equal(t, "test-owner", result.Owner)
+       assert.Equal(t, "test-env", result.Environment)
+       assert.Equal(t, "remote", result.MetadataType)
+       assert.Equal(t, "v1", result.Tag)
+       assert.Equal(t, "30880", result.MetadataServicePort)
+       assert.Equal(t, "triple", result.MetadataServiceProtocol)
+}
+
+// Test compatApplicationConfig with partial fields
+func TestCompatApplicationConfigPartial(t *testing.T) {
+       appCfg := &global.ApplicationConfig{
+               Name:    "test-app",
+               Version: "1.0.0",
+       }
+
+       result := compatApplicationConfig(appCfg)
+
+       assert.NotNil(t, result)
+       assert.Equal(t, "test-app", result.Name)
+       assert.Equal(t, "1.0.0", result.Version)
+       assert.Empty(t, result.Organization)
+       assert.Empty(t, result.Module)
+}
+
+// Test compatApplicationConfig with empty config
+func TestCompatApplicationConfigEmpty(t *testing.T) {
+       appCfg := &global.ApplicationConfig{}
+
+       result := compatApplicationConfig(appCfg)
+
+       assert.NotNil(t, result)
+       assert.Empty(t, result.Name)
+       assert.Empty(t, result.Organization)
+       assert.Empty(t, result.Module)
+       assert.Empty(t, result.Group)
+       assert.Empty(t, result.Version)
+       assert.Empty(t, result.Owner)
+       assert.Empty(t, result.Environment)
+       assert.Empty(t, result.MetadataType)
+       assert.Empty(t, result.Tag)
+       assert.Empty(t, result.MetadataServicePort)
+       assert.Empty(t, result.MetadataServiceProtocol)
+}
+
+// Test compatRegistryConfig with all fields
+func TestCompatRegistryConfigAll(t *testing.T) {
+       regCfg := &global.RegistryConfig{
+               Protocol:          "zookeeper",
+               Timeout:           "10s",
+               Group:             "registry-group",
+               Namespace:         "test-ns",
+               TTL:               "60s",
+               Address:           "localhost:2181",
+               Username:          "admin",
+               Password:          "password",
+               Simplified:        true,
+               Preferred:         true,
+               Zone:              "zone1",
+               Weight:            100,
+               Params:            map[string]string{"key": "value"},
+               RegistryType:      "service_discovery",
+               UseAsMetaReport:   "true",
+               UseAsConfigCenter: "true",
+       }
+
+       result := compatRegistryConfig(regCfg)
+
+       assert.NotNil(t, result)
+       assert.Equal(t, "zookeeper", result.Protocol)
+       assert.Equal(t, "10s", result.Timeout)
+       assert.Equal(t, "registry-group", result.Group)
+       assert.Equal(t, "test-ns", result.Namespace)
+       assert.Equal(t, "60s", result.TTL)
+       assert.Equal(t, "localhost:2181", result.Address)
+       assert.Equal(t, "admin", result.Username)
+       assert.Equal(t, "password", result.Password)
+       assert.True(t, result.Simplified)
+       assert.True(t, result.Preferred)
+       assert.Equal(t, "zone1", result.Zone)
+       assert.Equal(t, int64(100), result.Weight)
+       assert.Equal(t, "service_discovery", result.RegistryType)
+       assert.Equal(t, "true", result.UseAsMetaReport)
+       assert.Equal(t, "true", result.UseAsConfigCenter)
+       assert.NotNil(t, result.Params)
+       assert.Equal(t, "value", result.Params["key"])
+}
+
+// Test compatRegistryConfig with partial fields
+func TestCompatRegistryConfigPartial(t *testing.T) {
+       regCfg := &global.RegistryConfig{
+               Protocol: "nacos",
+               Address:  "localhost:8848",
+       }
+
+       result := compatRegistryConfig(regCfg)
+
+       assert.NotNil(t, result)
+       assert.Equal(t, "nacos", result.Protocol)
+       assert.Equal(t, "localhost:8848", result.Address)
+       assert.Empty(t, result.Timeout)
+       assert.Empty(t, result.Group)
+}
+
+// Test compatRegistryConfig with empty config
+func TestCompatRegistryConfigEmpty(t *testing.T) {
+       regCfg := &global.RegistryConfig{}
+
+       result := compatRegistryConfig(regCfg)
+
+       assert.NotNil(t, result)
+       assert.Empty(t, result.Protocol)
+       assert.Empty(t, result.Address)
+       assert.Empty(t, result.Timeout)
+       assert.Empty(t, result.Group)
+       assert.Empty(t, result.Namespace)
+       assert.Empty(t, result.TTL)
+       assert.Empty(t, result.Username)
+       assert.Empty(t, result.Password)
+       assert.False(t, result.Simplified)
+       assert.False(t, result.Preferred)
+}
+
+// Test compatRegistryConfig with boolean fields
+func TestCompatRegistryConfigBooleans(t *testing.T) {
+       regCfg := &global.RegistryConfig{
+               Protocol:          "etcd",
+               Simplified:        true,
+               Preferred:         true,
+               UseAsMetaReport:   "true",
+               UseAsConfigCenter: "false",
+       }
+
+       result := compatRegistryConfig(regCfg)
+
+       assert.NotNil(t, result)
+       assert.True(t, result.Simplified)
+       assert.True(t, result.Preferred)
+       assert.Equal(t, "true", result.UseAsMetaReport)
+       assert.Equal(t, "false", result.UseAsConfigCenter)
+}
+
+// Test compatRegistryConfig with numeric fields
+func TestCompatRegistryConfigNumeric(t *testing.T) {
+       regCfg := &global.RegistryConfig{
+               Protocol: "zookeeper",
+               Weight:   500,
+       }
+
+       result := compatRegistryConfig(regCfg)
+
+       assert.NotNil(t, result)
+       assert.Equal(t, "zookeeper", result.Protocol)
+       assert.Equal(t, int64(500), result.Weight)
+}
+
+// Test compatRegistryConfig with params
+func TestCompatRegistryConfigWithParams(t *testing.T) {
+       regCfg := &global.RegistryConfig{
+               Protocol: "zookeeper",
+               Params: map[string]string{
+                       "key1": "value1",
+                       "key2": "value2",
+                       "key3": "value3",
+               },
+       }
+
+       result := compatRegistryConfig(regCfg)
+
+       assert.NotNil(t, result)
+       assert.Equal(t, 3, len(result.Params))
+       assert.Equal(t, "value1", result.Params["key1"])
+       assert.Equal(t, "value2", result.Params["key2"])
+       assert.Equal(t, "value3", result.Params["key3"])
+}
+
+// Test compatApplicationConfig preserves all field types
+func TestCompatApplicationConfigFieldPreservation(t *testing.T) {
+       appCfg := &global.ApplicationConfig{
+               Name:                    "myapp",
+               Organization:            "myorg",
+               Module:                  "mymodule",
+               Group:                   "mygroup",
+               Version:                 "2.0.0",
+               Owner:                   "owner",
+               Environment:             "production",
+               MetadataType:            "local",
+               Tag:                     "beta",
+               MetadataServicePort:     "25555",
+               MetadataServiceProtocol: "grpc",
+       }
+
+       result := compatApplicationConfig(appCfg)
+
+       // Verify type conversion doesn't lose data
+       assert.IsType(t, (*config.ApplicationConfig)(nil), result)
+       assert.Equal(t, appCfg.Name, result.Name)
+       assert.Equal(t, appCfg.Organization, result.Organization)
+       assert.Equal(t, appCfg.Module, result.Module)
+}
+
+// Test compatRegistryConfig preserves all field types
+func TestCompatRegistryConfigFieldPreservation(t *testing.T) {
+       regCfg := &global.RegistryConfig{
+               Protocol:          "consul",
+               Timeout:           "30s",
+               Group:             "consul-group",
+               Namespace:         "consul-ns",
+               TTL:               "120s",
+               Address:           "localhost:8500",
+               Username:          "consul-user",
+               Password:          "consul-pass",
+               Simplified:        true,
+               Preferred:         false,
+               Zone:              "zone-a",
+               Weight:            200,
+               Params:            map[string]string{"consul-key": 
"consul-val"},
+               RegistryType:      "interface",
+               UseAsMetaReport:   "true",
+               UseAsConfigCenter: "false",
+       }
+
+       result := compatRegistryConfig(regCfg)
+
+       // Verify type conversion doesn't lose data
+       assert.IsType(t, (*config.RegistryConfig)(nil), result)
+       assert.Equal(t, regCfg.Protocol, result.Protocol)
+       assert.Equal(t, regCfg.Timeout, result.Timeout)
+       assert.Equal(t, regCfg.Group, result.Group)
+}
+
+// Test multiple conversions don't affect original
+func TestCompatConfigsPreservesOriginal(t *testing.T) {
+       appCfg := &global.ApplicationConfig{
+               Name:    "original-app",
+               Version: "1.0.0",
+       }
+
+       result1 := compatApplicationConfig(appCfg)
+       result2 := compatApplicationConfig(appCfg)
+
+       assert.Equal(t, "original-app", appCfg.Name)
+       assert.Equal(t, "1.0.0", appCfg.Version)
+
+       assert.Equal(t, result1.Name, result2.Name)
+       assert.Equal(t, result1.Version, result2.Version)
+       assert.Equal(t, "original-app", result1.Name)
+}
+
+// Test compatRegistryConfig with special characters in params
+func TestCompatRegistryConfigSpecialChars(t *testing.T) {
+       regCfg := &global.RegistryConfig{
+               Protocol: "zookeeper",
+               Params: map[string]string{
+                       "special.key":    "value with spaces",
+                       "another-key":    "value/with/slashes",
+                       "key_with_colon": "value:with:colons",
+                       "key.with.dots":  "value.with.dots",
+               },
+       }
+
+       result := compatRegistryConfig(regCfg)
+
+       assert.NotNil(t, result)
+       assert.Equal(t, "value with spaces", result.Params["special.key"])
+       assert.Equal(t, "value/with/slashes", result.Params["another-key"])
+       assert.Equal(t, "value:with:colons", result.Params["key_with_colon"])
+       assert.Equal(t, "value.with.dots", result.Params["key.with.dots"])
+}

Reply via email to