Copilot commented on code in PR #3124:
URL: https://github.com/apache/dubbo-go/pull/3124#discussion_r2637627505
##########
global/config_test.go:
##########
@@ -319,3 +319,1744 @@ func CheckCompleteInequality(t *testing.T, origin any,
clone any) {
}
}
}
+func TestReferenceConfigGetOptions(t *testing.T) {
+ t.Run("full_reference_config", func(t *testing.T) {
+ ref := &ReferenceConfig{
+ InterfaceName: "com.test.Service",
+ URL: "127.0.0.1:20880",
+ Filter: "echo",
+ Protocol: "dubbo",
+ Cluster: "failover",
+ Loadbalance: "random",
+ Retries: "3",
+ Group: "test",
+ Version: "1.0.0",
+ Serialization: "hessian2",
+ ProvidedBy: "provider",
+ Async: true,
+ Generic: "true",
+ Sticky: true,
+ RequestTimeout: "5s",
+ TracingKey: "jaeger",
+ MeshProviderPort: 8080,
+ KeepAliveInterval: "1m",
+ KeepAliveTimeout: "30s",
+ Params: map[string]string{
+ "key": "value",
+ },
+ Check: func() *bool { b := true; return &b }(),
+ RegistryIDs: []string{"reg1", "reg2"},
+ MethodsConfig: []*MethodConfig{
+ {Name: "method1"},
+ },
+ ProtocolClientConfig: DefaultClientProtocolConfig(),
+ }
+
+ opts := ref.GetOptions()
+ assert.NotNil(t, opts, "opts should not be nil")
+ assert.True(t, len(opts) > 0, "opts should have items")
+ })
+
+ t.Run("empty_reference_config", func(t *testing.T) {
+ emptyRef := &ReferenceConfig{}
+ emptyOpts := emptyRef.GetOptions()
+ // An empty config will return nil from GetOptions since all
fields are empty
+ if emptyOpts != nil {
+ assert.Equal(t, 0, len(emptyOpts), "empty ref config
should have no options")
+ }
+ })
+
+ t.Run("nil_reference_config_clone", func(t *testing.T) {
+ var nilRef *ReferenceConfig
+ cloned := nilRef.Clone()
+ assert.Nil(t, cloned)
+ })
Review Comment:
This test case "nil_reference_config_clone" is testing the Clone method but
is placed inside TestReferenceConfigGetOptions which is meant to test the
GetOptions method. This test should be moved to a separate test function or to
a more appropriate test group that focuses on cloning behavior.
##########
global/config_test.go:
##########
@@ -319,3 +319,1744 @@ func CheckCompleteInequality(t *testing.T, origin any,
clone any) {
}
}
}
+func TestReferenceConfigGetOptions(t *testing.T) {
+ t.Run("full_reference_config", func(t *testing.T) {
+ ref := &ReferenceConfig{
+ InterfaceName: "com.test.Service",
+ URL: "127.0.0.1:20880",
+ Filter: "echo",
+ Protocol: "dubbo",
+ Cluster: "failover",
+ Loadbalance: "random",
+ Retries: "3",
+ Group: "test",
+ Version: "1.0.0",
+ Serialization: "hessian2",
+ ProvidedBy: "provider",
+ Async: true,
+ Generic: "true",
+ Sticky: true,
+ RequestTimeout: "5s",
+ TracingKey: "jaeger",
+ MeshProviderPort: 8080,
+ KeepAliveInterval: "1m",
+ KeepAliveTimeout: "30s",
+ Params: map[string]string{
+ "key": "value",
+ },
+ Check: func() *bool { b := true; return &b }(),
+ RegistryIDs: []string{"reg1", "reg2"},
+ MethodsConfig: []*MethodConfig{
+ {Name: "method1"},
+ },
+ ProtocolClientConfig: DefaultClientProtocolConfig(),
+ }
+
+ opts := ref.GetOptions()
+ assert.NotNil(t, opts, "opts should not be nil")
+ assert.True(t, len(opts) > 0, "opts should have items")
+ })
+
+ t.Run("empty_reference_config", func(t *testing.T) {
+ emptyRef := &ReferenceConfig{}
+ emptyOpts := emptyRef.GetOptions()
+ // An empty config will return nil from GetOptions since all
fields are empty
+ if emptyOpts != nil {
+ assert.Equal(t, 0, len(emptyOpts), "empty ref config
should have no options")
+ }
+ })
+
+ t.Run("nil_reference_config_clone", func(t *testing.T) {
+ var nilRef *ReferenceConfig
+ cloned := nilRef.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("reference_config_with_retries_parsing", func(t *testing.T) {
+ ref := &ReferenceConfig{
+ Retries: "5",
+ }
+ opts := ref.GetOptions()
+ assert.NotNil(t, opts)
+ // Verify that a valid retries value produces an option
+ assert.Greater(t, len(opts), 0, "should have at least one
option from Retries")
+ // Verify retries option is present by checking that we have
options
+ hasRetriesOption := false
+ for _, opt := range opts {
+ // The option function should be WithReference_Retries
+ if opt != nil {
+ hasRetriesOption = true
+ break
+ }
+ }
+ assert.True(t, hasRetriesOption, "should contain a
retries-related option when Retries is a valid integer")
+ })
+
+ t.Run("reference_config_with_invalid_retries", func(t *testing.T) {
+ ref := &ReferenceConfig{
+ Retries: "invalid",
+ }
+ opts := ref.GetOptions()
+ // Invalid retries should not be added to options
+ // This is expected behavior - invalid values are silently
skipped
+ // Verify the returned options do not contain a retries option
+ // by confirming the invalid string is not converted
+
+ // GetOptions returns nil (or empty slice) when no options are
present
+ // Since Retries is the only field and it's invalid, no options
should be produced
+ if opts != nil {
+ // If opts is returned as a slice, it should be empty
since Retries is invalid
+ assert.Equal(t, 0, len(opts), "invalid retries value
should not produce any options")
+ }
+ // The fact that invalid retries is not in opts confirms it was
rejected
+ t.Logf("Invalid retries value was correctly skipped (opts=%v)",
opts)
Review Comment:
This t.Logf statement appears to be debugging code that should be removed.
Logging in tests should generally be used for diagnostic purposes during test
failures, not to confirm expected behavior. Since this test is verifying
expected behavior (invalid retries being skipped), the log statement doesn't
add value and creates noise in test output.
```suggestion
```
##########
global/config_test.go:
##########
@@ -319,3 +319,1744 @@ func CheckCompleteInequality(t *testing.T, origin any,
clone any) {
}
}
}
+func TestReferenceConfigGetOptions(t *testing.T) {
+ t.Run("full_reference_config", func(t *testing.T) {
+ ref := &ReferenceConfig{
+ InterfaceName: "com.test.Service",
+ URL: "127.0.0.1:20880",
+ Filter: "echo",
+ Protocol: "dubbo",
+ Cluster: "failover",
+ Loadbalance: "random",
+ Retries: "3",
+ Group: "test",
+ Version: "1.0.0",
+ Serialization: "hessian2",
+ ProvidedBy: "provider",
+ Async: true,
+ Generic: "true",
+ Sticky: true,
+ RequestTimeout: "5s",
+ TracingKey: "jaeger",
+ MeshProviderPort: 8080,
+ KeepAliveInterval: "1m",
+ KeepAliveTimeout: "30s",
+ Params: map[string]string{
+ "key": "value",
+ },
+ Check: func() *bool { b := true; return &b }(),
+ RegistryIDs: []string{"reg1", "reg2"},
+ MethodsConfig: []*MethodConfig{
+ {Name: "method1"},
+ },
+ ProtocolClientConfig: DefaultClientProtocolConfig(),
+ }
+
+ opts := ref.GetOptions()
+ assert.NotNil(t, opts, "opts should not be nil")
+ assert.True(t, len(opts) > 0, "opts should have items")
+ })
+
+ t.Run("empty_reference_config", func(t *testing.T) {
+ emptyRef := &ReferenceConfig{}
+ emptyOpts := emptyRef.GetOptions()
+ // An empty config will return nil from GetOptions since all
fields are empty
+ if emptyOpts != nil {
+ assert.Equal(t, 0, len(emptyOpts), "empty ref config
should have no options")
+ }
+ })
+
+ t.Run("nil_reference_config_clone", func(t *testing.T) {
+ var nilRef *ReferenceConfig
+ cloned := nilRef.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("reference_config_with_retries_parsing", func(t *testing.T) {
+ ref := &ReferenceConfig{
+ Retries: "5",
+ }
+ opts := ref.GetOptions()
+ assert.NotNil(t, opts)
+ // Verify that a valid retries value produces an option
+ assert.Greater(t, len(opts), 0, "should have at least one
option from Retries")
+ // Verify retries option is present by checking that we have
options
+ hasRetriesOption := false
+ for _, opt := range opts {
+ // The option function should be WithReference_Retries
+ if opt != nil {
+ hasRetriesOption = true
+ break
+ }
+ }
+ assert.True(t, hasRetriesOption, "should contain a
retries-related option when Retries is a valid integer")
+ })
+
+ t.Run("reference_config_with_invalid_retries", func(t *testing.T) {
+ ref := &ReferenceConfig{
+ Retries: "invalid",
+ }
+ opts := ref.GetOptions()
+ // Invalid retries should not be added to options
+ // This is expected behavior - invalid values are silently
skipped
+ // Verify the returned options do not contain a retries option
+ // by confirming the invalid string is not converted
+
+ // GetOptions returns nil (or empty slice) when no options are
present
+ // Since Retries is the only field and it's invalid, no options
should be produced
+ if opts != nil {
+ // If opts is returned as a slice, it should be empty
since Retries is invalid
+ assert.Equal(t, 0, len(opts), "invalid retries value
should not produce any options")
+ }
+ // The fact that invalid retries is not in opts confirms it was
rejected
+ t.Logf("Invalid retries value was correctly skipped (opts=%v)",
opts)
+ })
+}
+
+// TestReferenceConfigOptions tests the option functions
+func TestReferenceConfigOptions(t *testing.T) {
+ t.Run("WithReference_InterfaceName", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_InterfaceName("com.test.Service")
+ opt(ref)
+ assert.Equal(t, "com.test.Service", ref.InterfaceName)
+ })
+
+ t.Run("WithReference_Check_true", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Check(true)
+ opt(ref)
+ assert.NotNil(t, ref.Check)
+ assert.True(t, *ref.Check)
+ })
+
+ t.Run("WithReference_Check_false", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Check(false)
+ opt(ref)
+ assert.NotNil(t, ref.Check)
+ assert.False(t, *ref.Check)
+ })
+
+ t.Run("WithReference_URL", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_URL("127.0.0.1:20880")
+ opt(ref)
+ assert.Equal(t, "127.0.0.1:20880", ref.URL)
+ })
+
+ t.Run("WithReference_Filter", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Filter("echo")
+ opt(ref)
+ assert.Equal(t, "echo", ref.Filter)
+ })
+
+ t.Run("WithReference_Protocol", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Protocol("tri")
+ opt(ref)
+ assert.Equal(t, "tri", ref.Protocol)
+ })
+
+ t.Run("WithReference_RegistryIDs", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_RegistryIDs([]string{"reg1", "reg2"})
+ opt(ref)
+ assert.Equal(t, 2, len(ref.RegistryIDs))
+ assert.Equal(t, "reg1", ref.RegistryIDs[0])
+ assert.Equal(t, "reg2", ref.RegistryIDs[1])
+ })
+
+ t.Run("WithReference_RegistryIDs_empty", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_RegistryIDs([]string{})
+ opt(ref)
+ assert.Equal(t, 0, len(ref.RegistryIDs))
+ })
+
+ t.Run("WithReference_Cluster", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Cluster("failover")
+ opt(ref)
+ assert.Equal(t, "failover", ref.Cluster)
+ })
+
+ t.Run("WithReference_LoadBalance", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_LoadBalance("random")
+ opt(ref)
+ assert.Equal(t, "random", ref.Loadbalance)
+ })
+
+ t.Run("WithReference_Retries", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Retries(3)
+ opt(ref)
+ assert.Equal(t, "3", ref.Retries)
+ })
+
+ t.Run("WithReference_Group", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Group("test")
+ opt(ref)
+ assert.Equal(t, "test", ref.Group)
+ })
+
+ t.Run("WithReference_Version", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Version("1.0.0")
+ opt(ref)
+ assert.Equal(t, "1.0.0", ref.Version)
+ })
+
+ t.Run("WithReference_Serialization", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Serialization("hessian2")
+ opt(ref)
+ assert.Equal(t, "hessian2", ref.Serialization)
+ })
+
+ t.Run("WithReference_ProviderBy", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_ProviderBy("provider")
+ opt(ref)
+ assert.Equal(t, "provider", ref.ProvidedBy)
+ })
+
+ t.Run("WithReference_Async_true", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Async(true)
+ opt(ref)
+ assert.True(t, ref.Async)
+ })
+
+ t.Run("WithReference_Async_false", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Async(false)
+ opt(ref)
+ assert.False(t, ref.Async)
+ })
+
+ t.Run("WithReference_Params", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ params := map[string]string{"key": "value", "key2": "value2"}
+ opt := WithReference_Params(params)
+ opt(ref)
+ assert.Equal(t, "value", ref.Params["key"])
+ assert.Equal(t, "value2", ref.Params["key2"])
+ })
+
+ t.Run("WithReference_Generic", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Generic("true")
+ opt(ref)
+ assert.Equal(t, "true", ref.Generic)
+ })
+
+ t.Run("WithReference_Sticky", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Sticky(true)
+ opt(ref)
+ assert.True(t, ref.Sticky)
+ })
+
+ t.Run("WithReference_RequestTimeout", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_RequestTimeout("5s")
+ opt(ref)
+ assert.Equal(t, "5s", ref.RequestTimeout)
+ })
+
+ t.Run("WithReference_Force", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Force(true)
+ opt(ref)
+ assert.True(t, ref.ForceTag)
+ })
+
+ t.Run("WithReference_TracingKey", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_TracingKey("jaeger")
+ opt(ref)
+ assert.Equal(t, "jaeger", ref.TracingKey)
+ })
+
+ t.Run("WithReference_MeshProviderPort", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_MeshProviderPort(8080)
+ opt(ref)
+ assert.Equal(t, 8080, ref.MeshProviderPort)
+ })
+
+ t.Run("WithReference_KeepAliveInterval", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_KeepAliveInterval("1m")
+ opt(ref)
+ assert.Equal(t, "1m", ref.KeepAliveInterval)
+ })
+
+ t.Run("WithReference_KeepAliveTimeout", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_KeepAliveTimeout("30s")
+ opt(ref)
+ assert.Equal(t, "30s", ref.KeepAliveTimeout)
+ })
+
+ t.Run("WithReference_ProtocolClientConfig", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ pcc := DefaultClientProtocolConfig()
+ opt := WithReference_ProtocolClientConfig(pcc)
+ opt(ref)
+ assert.NotNil(t, ref.ProtocolClientConfig)
+ })
+}
+func TestRegistryConfigUseAsMetadataReport(t *testing.T) {
+ t.Run("empty_use_as_meta_report_defaults_to_true", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: ""}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.True(t, result)
+ })
+
+ t.Run("true_string", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "true"}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.True(t, result)
+ })
+
+ t.Run("false_string", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "false"}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.False(t, result)
+ })
+
+ t.Run("TRUE_uppercase", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "TRUE"}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.True(t, result)
+ })
+
+ t.Run("FALSE_uppercase", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "FALSE"}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.False(t, result)
+ })
+
+ t.Run("invalid_use_as_meta_report", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "invalid"}
+ result, err := reg.UseAsMetadataReport()
+ assert.NotNil(t, err)
+ assert.False(t, result)
+ })
+
+ t.Run("1_as_true", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "1"}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.True(t, result)
+ })
+
+ t.Run("0_as_false", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "0"}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.False(t, result)
+ })
+}
+
+// TestRegistryConfigClone tests the Clone method of RegistryConfig
+func TestRegistryConfigClone(t *testing.T) {
+ t.Run("clone_full_registry_config", func(t *testing.T) {
+ reg := &RegistryConfig{
+ Protocol: "zookeeper",
+ Timeout: "5s",
+ Group: "test",
+ Namespace: "ns",
+ TTL: "15m",
+ Address: "localhost:2181",
+ Username: "user",
+ Password: "pass",
+ Simplified: true,
+ Preferred: true,
+ Zone: "zone1",
+ Weight: 100,
+ UseAsMetaReport: "true",
+ UseAsConfigCenter: "true",
+ RegistryType: "nacos",
+ Params: map[string]string{
+ "key1": "value1",
+ "key2": "value2",
+ },
+ }
+ cloned := reg.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, reg.Protocol, cloned.Protocol)
+ assert.Equal(t, reg.Timeout, cloned.Timeout)
+ assert.Equal(t, reg.Group, cloned.Group)
+ assert.Equal(t, reg.Namespace, cloned.Namespace)
+ assert.Equal(t, reg.TTL, cloned.TTL)
+ assert.Equal(t, reg.Address, cloned.Address)
+ assert.Equal(t, reg.Username, cloned.Username)
+ assert.Equal(t, reg.Password, cloned.Password)
+ assert.Equal(t, reg.Simplified, cloned.Simplified)
+ assert.Equal(t, reg.Preferred, cloned.Preferred)
+ assert.Equal(t, reg.Zone, cloned.Zone)
+ assert.Equal(t, reg.Weight, cloned.Weight)
+ assert.Equal(t, reg.UseAsMetaReport, cloned.UseAsMetaReport)
+ assert.Equal(t, reg.UseAsConfigCenter, cloned.UseAsConfigCenter)
+ assert.NotSame(t, reg, cloned)
+ assert.NotSame(t, reg.Params, cloned.Params)
+ assert.Equal(t, "value1", cloned.Params["key1"])
+ assert.Equal(t, "value2", cloned.Params["key2"])
+ })
+
+ t.Run("clone_nil_registry_config", func(t *testing.T) {
+ var reg *RegistryConfig
+ cloned := reg.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_empty_registry_config", func(t *testing.T) {
+ reg := &RegistryConfig{}
+ cloned := reg.Clone()
+ assert.NotNil(t, cloned)
+ assert.NotSame(t, reg, cloned)
+ })
+
+ t.Run("clone_with_empty_params", func(t *testing.T) {
+ reg := &RegistryConfig{
+ Protocol: "nacos",
+ Params: make(map[string]string),
+ }
+ cloned := reg.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, 0, len(cloned.Params))
+ assert.NotSame(t, reg.Params, cloned.Params)
+ })
+}
+
+// TestDefaultRegistryConfig tests DefaultRegistryConfig function
+func TestDefaultRegistryConfig(t *testing.T) {
+ t.Run("default_registry_config", func(t *testing.T) {
+ reg := DefaultRegistryConfig()
+ assert.NotNil(t, reg)
+ assert.Equal(t, "true", reg.UseAsMetaReport)
+ assert.Equal(t, "true", reg.UseAsConfigCenter)
+ assert.Equal(t, "5s", reg.Timeout)
+ assert.Equal(t, "15m", reg.TTL)
+ })
+}
+
+// TestDefaultRegistriesConfig tests DefaultRegistriesConfig function
+func TestDefaultRegistriesConfig(t *testing.T) {
+ t.Run("default_registries_config", func(t *testing.T) {
+ regs := DefaultRegistriesConfig()
+ assert.NotNil(t, regs)
+ assert.Equal(t, 0, len(regs))
+ })
+}
+
+// TestCloneRegistriesConfig tests CloneRegistriesConfig function
+func TestCloneRegistriesConfig(t *testing.T) {
+ t.Run("clone_multiple_registries", func(t *testing.T) {
+ regs := map[string]*RegistryConfig{
+ "reg1": {
+ Protocol: "zookeeper",
+ Address: "localhost:2181",
+ Params: map[string]string{
+ "key": "value",
+ },
+ },
+ "reg2": {
+ Protocol: "nacos",
+ Address: "localhost:8848",
+ Params: map[string]string{
+ "key2": "value2",
+ },
+ },
+ }
+ cloned := CloneRegistriesConfig(regs)
+ assert.Equal(t, 2, len(cloned))
+ assert.Equal(t, "zookeeper", cloned["reg1"].Protocol)
+ assert.Equal(t, "nacos", cloned["reg2"].Protocol)
+ assert.NotSame(t, regs["reg1"], cloned["reg1"])
+ assert.NotSame(t, regs["reg2"], cloned["reg2"])
+ assert.Equal(t, "value", cloned["reg1"].Params["key"])
+ assert.Equal(t, "value2", cloned["reg2"].Params["key2"])
+ })
+
+ t.Run("clone_nil_registries_config", func(t *testing.T) {
+ var regs map[string]*RegistryConfig
+ cloned := CloneRegistriesConfig(regs)
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_empty_registries_config", func(t *testing.T) {
+ regs := make(map[string]*RegistryConfig)
+ cloned := CloneRegistriesConfig(regs)
+ assert.NotNil(t, cloned)
+ assert.Equal(t, 0, len(cloned))
+ assert.NotSame(t, regs, cloned)
+ })
+
+ t.Run("clone_single_registry", func(t *testing.T) {
+ regs := map[string]*RegistryConfig{
+ "reg1": {
+ Protocol: "etcdv3",
+ Timeout: "10s",
+ Weight: 50,
+ Preferred: true,
+ },
+ }
+ cloned := CloneRegistriesConfig(regs)
+ assert.Equal(t, 1, len(cloned))
+ assert.Equal(t, "etcdv3", cloned["reg1"].Protocol)
+ assert.Equal(t, "10s", cloned["reg1"].Timeout)
+ assert.Equal(t, int64(50), cloned["reg1"].Weight)
+ assert.True(t, cloned["reg1"].Preferred)
+ })
+}
+func TestRouterConfigClone(t *testing.T) {
+ t.Run("clone_full_router_config", func(t *testing.T) {
+ router := &RouterConfig{
+ Scope: "service",
+ Key: "com.test.Service",
+ Priority: 10,
+ ScriptType: "javascript",
+ Script: "1==1",
+ Force: func() *bool {
+ b := true
+ return &b
+ }(),
+ Runtime: func() *bool {
+ b := false
+ return &b
+ }(),
+ Enabled: func() *bool {
+ b := true
+ return &b
+ }(),
+ Valid: func() *bool {
+ b := true
+ return &b
+ }(),
+ Conditions: []string{"condition1", "condition2"},
+ Tags: []Tag{
+ {
+ Name: "tag1",
+ Addresses: []string{"addr1", "addr2"},
+ },
+ {
+ Name: "tag2",
+ Addresses: []string{"addr3"},
+ },
+ },
+ }
+
+ cloned := router.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, router.Scope, cloned.Scope)
+ assert.Equal(t, router.Key, cloned.Key)
+ assert.Equal(t, router.Priority, cloned.Priority)
+ assert.Equal(t, router.ScriptType, cloned.ScriptType)
+ assert.Equal(t, router.Script, cloned.Script)
+ assert.NotSame(t, router, cloned)
+ assert.NotSame(t, router.Conditions, cloned.Conditions)
+ assert.NotSame(t, router.Tags, cloned.Tags)
+ assert.Equal(t, 2, len(cloned.Conditions))
+ assert.Equal(t, 2, len(cloned.Tags))
+ assert.Equal(t, "tag1", cloned.Tags[0].Name)
+ assert.Equal(t, "tag2", cloned.Tags[1].Name)
+ assert.Equal(t, 2, len(cloned.Tags[0].Addresses))
+ assert.Equal(t, 1, len(cloned.Tags[1].Addresses))
+ })
+
+ t.Run("clone_nil_router_config", func(t *testing.T) {
+ var router *RouterConfig
+ cloned := router.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_empty_router_config", func(t *testing.T) {
+ router := &RouterConfig{}
+ cloned := router.Clone()
+ assert.NotNil(t, cloned)
+ assert.NotSame(t, router, cloned)
+ })
+
+ t.Run("clone_router_config_with_nil_pointers", func(t *testing.T) {
+ router := &RouterConfig{
+ Scope: "service",
+ Key: "com.test.Service",
+ Force: nil,
+ Runtime: nil,
+ }
+ cloned := router.Clone()
+ assert.NotNil(t, cloned)
+ assert.Nil(t, cloned.Force)
+ assert.Nil(t, cloned.Runtime)
+ })
+
+ t.Run("clone_router_config_preserves_pointer_values", func(t
*testing.T) {
+ forceTrue := true
+ runtimeFalse := false
+ router := &RouterConfig{
+ Scope: "service",
+ Key: "test",
+ Force: &forceTrue,
+ Runtime: &runtimeFalse,
+ }
+ cloned := router.Clone()
+ assert.NotNil(t, cloned.Force)
+ assert.NotNil(t, cloned.Runtime)
+ assert.True(t, *cloned.Force)
+ assert.False(t, *cloned.Runtime)
+ assert.NotSame(t, router.Force, cloned.Force)
+ assert.NotSame(t, router.Runtime, cloned.Runtime)
+ })
+}
+
+// TestDefaultRouterConfig tests DefaultRouterConfig function
+func TestDefaultRouterConfig(t *testing.T) {
+ t.Run("default_router_config", func(t *testing.T) {
+ router := DefaultRouterConfig()
+ assert.NotNil(t, router)
+ assert.Equal(t, 0, len(router.Conditions))
+ assert.Equal(t, 0, len(router.Tags))
+ })
+}
+
+// TestTagStructure tests Tag structure and cloning
+func TestTagStructure(t *testing.T) {
+ t.Run("tag_with_addresses", func(t *testing.T) {
+ tag := Tag{
+ Name: "test",
+ Addresses: []string{"addr1", "addr2"},
+ }
+ assert.Equal(t, "test", tag.Name)
+ assert.Equal(t, 2, len(tag.Addresses))
+ })
+
+ t.Run("tag_with_empty_addresses", func(t *testing.T) {
+ tag := Tag{
+ Name: "test",
+ Addresses: []string{},
+ }
+ assert.Equal(t, 0, len(tag.Addresses))
+ })
+}
+
+// TestRouterConfigFields tests individual fields of RouterConfig
+func TestRouterConfigFields(t *testing.T) {
+ t.Run("router_config_scope", func(t *testing.T) {
+ router := &RouterConfig{
+ Scope: "application",
+ }
+ assert.Equal(t, "application", router.Scope)
+ })
+
+ t.Run("router_config_priority", func(t *testing.T) {
+ router := &RouterConfig{
+ Priority: 100,
+ }
+ assert.Equal(t, 100, router.Priority)
+ })
+
+ t.Run("router_config_script_type", func(t *testing.T) {
+ router := &RouterConfig{
+ ScriptType: "groovy",
+ Script: "1 == 1",
+ }
+ assert.Equal(t, "groovy", router.ScriptType)
+ assert.Equal(t, "1 == 1", router.Script)
+ })
+
+ t.Run("router_config_conditions_multiple", func(t *testing.T) {
+ router := &RouterConfig{
+ Conditions: []string{"cond1", "cond2", "cond3"},
+ }
+ assert.Equal(t, 3, len(router.Conditions))
+ assert.Equal(t, "cond1", router.Conditions[0])
+ assert.Equal(t, "cond3", router.Conditions[2])
+ })
+}
+func TestProtocolConfigClone(t *testing.T) {
+ t.Run("clone_full_protocol_config", func(t *testing.T) {
+ proto := &ProtocolConfig{
+ Name: "tri",
+ Ip: "127.0.0.1",
+ Port: "20880",
+ MaxServerSendMsgSize: "1mb",
+ MaxServerRecvMsgSize: "4mb",
+ TripleConfig: &TripleConfig{
+ MaxServerSendMsgSize: "2mb",
+ MaxServerRecvMsgSize: "4mb",
+ KeepAliveInterval: "1m",
+ KeepAliveTimeout: "30s",
+ Http3: DefaultHttp3Config(),
+ },
+ Params: map[string]string{
+ "key1": "value1",
+ "key2": "value2",
+ },
+ }
+
+ cloned := proto.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, proto.Name, cloned.Name)
+ assert.Equal(t, proto.Ip, cloned.Ip)
+ assert.Equal(t, proto.Port, cloned.Port)
+ assert.Equal(t, proto.MaxServerSendMsgSize,
cloned.MaxServerSendMsgSize)
+ assert.Equal(t, proto.MaxServerRecvMsgSize,
cloned.MaxServerRecvMsgSize)
+ assert.NotSame(t, proto, cloned)
+ assert.NotSame(t, proto.TripleConfig, cloned.TripleConfig)
+ assert.NotNil(t, cloned.TripleConfig)
+ })
+
+ t.Run("clone_nil_protocol_config", func(t *testing.T) {
+ var proto *ProtocolConfig
+ cloned := proto.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_protocol_config_with_nil_triple_config", func(t
*testing.T) {
+ proto := &ProtocolConfig{
+ Name: "dubbo",
+ Port: "20880",
+ }
+ cloned := proto.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, "dubbo", cloned.Name)
+ })
+
+ t.Run("clone_protocol_config_preserves_all_fields", func(t *testing.T) {
+ proto := &ProtocolConfig{
+ Name: "http",
+ Ip: "192.168.1.1",
+ Port: "8080",
+ MaxServerSendMsgSize: "10mb",
+ MaxServerRecvMsgSize: "10mb",
+ }
+ cloned := proto.Clone()
+ assert.Equal(t, "http", cloned.Name)
+ assert.Equal(t, "192.168.1.1", cloned.Ip)
+ assert.Equal(t, "8080", cloned.Port)
+ assert.Equal(t, "10mb", cloned.MaxServerSendMsgSize)
+ assert.Equal(t, "10mb", cloned.MaxServerRecvMsgSize)
+ })
+}
+
+// TestDefaultProtocolConfig tests DefaultProtocolConfig function
+func TestDefaultProtocolConfig(t *testing.T) {
+ t.Run("default_protocol_config", func(t *testing.T) {
+ proto := DefaultProtocolConfig()
+ assert.NotNil(t, proto)
+ assert.NotEmpty(t, proto.Name)
+ assert.NotEmpty(t, proto.Port)
+ assert.NotNil(t, proto.TripleConfig)
+ })
+}
+
+// TestProtocolConfigFields tests individual fields of ProtocolConfig
+func TestProtocolConfigFields(t *testing.T) {
+ t.Run("protocol_config_name", func(t *testing.T) {
+ proto := &ProtocolConfig{Name: "dubbo"}
+ assert.Equal(t, "dubbo", proto.Name)
+ })
+
+ t.Run("protocol_config_ip", func(t *testing.T) {
+ proto := &ProtocolConfig{Ip: "10.0.0.1"}
+ assert.Equal(t, "10.0.0.1", proto.Ip)
+ })
+
+ t.Run("protocol_config_port", func(t *testing.T) {
+ proto := &ProtocolConfig{Port: "9090"}
+ assert.Equal(t, "9090", proto.Port)
+ })
+
+ t.Run("protocol_config_with_params", func(t *testing.T) {
+ params := map[string]string{
+ "param1": "value1",
+ "param2": "value2",
+ }
+ proto := &ProtocolConfig{
+ Name: "tri",
+ Params: params,
+ }
+ assert.NotNil(t, proto.Params)
+ })
+
+ t.Run("protocol_config_with_triple_config", func(t *testing.T) {
+ tripleConfig := &TripleConfig{
+ KeepAliveInterval: "2m",
+ KeepAliveTimeout: "60s",
+ }
+ proto := &ProtocolConfig{
+ Name: "tri",
+ TripleConfig: tripleConfig,
+ }
+ assert.NotNil(t, proto.TripleConfig)
+ assert.Equal(t, "2m", proto.TripleConfig.KeepAliveInterval)
+ assert.Equal(t, "60s", proto.TripleConfig.KeepAliveTimeout)
+ })
+}
+
+// TestTripleConfigClone tests the Clone method of TripleConfig
+func TestTripleConfigClone(t *testing.T) {
+ t.Run("clone_full_triple_config", func(t *testing.T) {
+ triple := &TripleConfig{
+ MaxServerSendMsgSize: "5mb",
+ MaxServerRecvMsgSize: "5mb",
+ KeepAliveInterval: "3m",
+ KeepAliveTimeout: "45s",
+ Http3: DefaultHttp3Config(),
+ }
+ cloned := triple.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, triple.MaxServerSendMsgSize,
cloned.MaxServerSendMsgSize)
+ assert.Equal(t, triple.MaxServerRecvMsgSize,
cloned.MaxServerRecvMsgSize)
+ assert.Equal(t, triple.KeepAliveInterval,
cloned.KeepAliveInterval)
+ assert.Equal(t, triple.KeepAliveTimeout,
cloned.KeepAliveTimeout)
+ assert.NotSame(t, triple, cloned)
+ assert.NotSame(t, triple.Http3, cloned.Http3)
+ })
+
+ t.Run("clone_nil_triple_config", func(t *testing.T) {
+ var triple *TripleConfig
+ cloned := triple.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_triple_config_with_nil_http3", func(t *testing.T) {
+ triple := &TripleConfig{
+ MaxServerSendMsgSize: "1mb",
+ }
+ cloned := triple.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, "1mb", cloned.MaxServerSendMsgSize)
+ })
+}
+
+// TestDefaultTripleConfig tests DefaultTripleConfig function
+func TestDefaultTripleConfig(t *testing.T) {
+ t.Run("default_triple_config", func(t *testing.T) {
+ triple := DefaultTripleConfig()
+ assert.NotNil(t, triple)
+ assert.NotNil(t, triple.Http3)
+ })
+}
+
+// TestHttp3ConfigClone tests the Clone method of Http3Config
+func TestHttp3ConfigClone(t *testing.T) {
+ t.Run("clone_http3_config", func(t *testing.T) {
+ http3 := &Http3Config{
+ Enable: true,
+ Negotiation: false,
+ }
+ cloned := http3.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, http3.Enable, cloned.Enable)
+ assert.Equal(t, http3.Negotiation, cloned.Negotiation)
+ })
+
+ t.Run("clone_nil_http3_config", func(t *testing.T) {
+ var http3 *Http3Config
+ cloned := http3.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_http3_config_with_defaults", func(t *testing.T) {
+ http3 := DefaultHttp3Config()
+ cloned := http3.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, http3.Enable, cloned.Enable)
+ assert.Equal(t, http3.Negotiation, cloned.Negotiation)
+ })
+}
+
+// TestDefaultHttp3Config tests DefaultHttp3Config function
+func TestDefaultHttp3Config(t *testing.T) {
+ t.Run("default_http3_config", func(t *testing.T) {
+ http3 := DefaultHttp3Config()
+ assert.NotNil(t, http3)
+ })
+}
+func TestConsumerConfigClone(t *testing.T) {
+ t.Run("clone_full_consumer_config", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ Filter: "echo",
+ Protocol: "dubbo",
+ RequestTimeout: "5s",
+ ProxyFactory: "default",
+ Check: true,
+ AdaptiveService: true,
+ TracingKey: "jaeger",
+ MeshEnabled: true,
+ MaxWaitTimeForServiceDiscovery: "5s",
+ RegistryIDs: []string{"reg1",
"reg2"},
+ References: map[string]*ReferenceConfig{
+ "ref1": {
+ InterfaceName: "com.test.Service1",
+ },
+ "ref2": {
+ InterfaceName: "com.test.Service2",
+ },
+ },
+ }
+
+ cloned := consumer.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, consumer.Filter, cloned.Filter)
+ assert.Equal(t, consumer.Protocol, cloned.Protocol)
+ assert.Equal(t, consumer.RequestTimeout, cloned.RequestTimeout)
+ assert.Equal(t, consumer.Check, cloned.Check)
+ assert.Equal(t, consumer.AdaptiveService,
cloned.AdaptiveService)
+ assert.NotSame(t, consumer, cloned)
+ assert.NotSame(t, consumer.References, cloned.References)
+ assert.Equal(t, 2, len(cloned.References))
+ assert.Equal(t, "com.test.Service1",
cloned.References["ref1"].InterfaceName)
+ })
+
+ t.Run("clone_nil_consumer_config", func(t *testing.T) {
+ var consumer *ConsumerConfig
+ cloned := consumer.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_consumer_config_with_empty_references", func(t *testing.T)
{
+ consumer := &ConsumerConfig{
+ Filter: "echo",
+ }
+ cloned := consumer.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, "echo", cloned.Filter)
+ assert.NotSame(t, consumer, cloned)
+ })
+}
+
+// TestDefaultConsumerConfig tests DefaultConsumerConfig function
+func TestDefaultConsumerConfig(t *testing.T) {
+ t.Run("default_consumer_config", func(t *testing.T) {
+ consumer := DefaultConsumerConfig()
+ assert.NotNil(t, consumer)
+ assert.True(t, consumer.Check)
+ assert.NotNil(t, consumer.References)
+ assert.Equal(t, 0, len(consumer.References))
+ })
+}
+
+// TestConsumerConfigFields tests individual fields of ConsumerConfig
+func TestConsumerConfigFields(t *testing.T) {
+ t.Run("consumer_config_filter", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ Filter: "echo",
+ }
+ assert.Equal(t, "echo", consumer.Filter)
+ })
+
+ t.Run("consumer_config_protocol", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ Protocol: "tri",
+ }
+ assert.Equal(t, "tri", consumer.Protocol)
+ })
+
+ t.Run("consumer_config_timeout", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ RequestTimeout: "10s",
+ }
+ assert.Equal(t, "10s", consumer.RequestTimeout)
+ })
+
+ t.Run("consumer_config_check", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ Check: false,
+ }
+ assert.False(t, consumer.Check)
+ })
+
+ t.Run("consumer_config_adaptive_service", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ AdaptiveService: true,
+ }
+ assert.True(t, consumer.AdaptiveService)
+ })
+
+ t.Run("consumer_config_registry_ids", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ RegistryIDs: []string{"reg1", "reg2", "reg3"},
+ }
+ assert.Equal(t, 3, len(consumer.RegistryIDs))
+ })
+
+ t.Run("consumer_config_mesh_enabled", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ MeshEnabled: true,
+ }
+ assert.True(t, consumer.MeshEnabled)
+ })
+}
+func TestServiceConfigClone(t *testing.T) {
+ t.Run("clone_full_service_config", func(t *testing.T) {
+ service := &ServiceConfig{
+ Filter: "echo",
+ Interface: "com.test.Service",
+ Group: "test",
+ Version: "1.0.0",
+ Cluster: "failover",
+ Loadbalance: "random",
+ NotRegister: true,
+ Weight: 100,
+ TracingKey: "jaeger",
+ Auth: "token",
+ Token: "abc123",
+ AccessLog: "true",
+ TpsLimiter: "default",
+ TpsLimitInterval: "1000",
+ TpsLimitRate: "100",
+ TpsLimitStrategy: "default",
+ ExecuteLimit: "10",
+ ExecuteLimitRejectedHandler: "default",
+ ParamSign: "true",
+ Tag: "prod",
+ Warmup: "60",
+ Retries: "3",
+ Serialization: "hessian2",
+ ProtocolIDs: []string{"proto1"},
+ RegistryIDs: []string{"reg1"},
+ Methods: []*MethodConfig{
+ {Name: "method1"},
+ },
+ Params: map[string]string{
+ "key": "value",
+ },
+ RCProtocolsMap: map[string]*ProtocolConfig{
+ "proto1": {Name: "tri"},
+ },
+ RCRegistriesMap: map[string]*RegistryConfig{
+ "reg1": {Protocol: "zookeeper"},
+ },
+ }
+
+ cloned := service.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, service.Filter, cloned.Filter)
+ assert.Equal(t, service.Interface, cloned.Interface)
+ assert.Equal(t, service.Group, cloned.Group)
+ assert.Equal(t, service.Version, cloned.Version)
+ assert.NotSame(t, service, cloned)
+ assert.NotSame(t, service.Params, cloned.Params)
+ assert.Equal(t, "value", cloned.Params["key"])
+ assert.Equal(t, 1, len(cloned.ProtocolIDs))
+ assert.Equal(t, 1, len(cloned.RegistryIDs))
+ })
+
+ t.Run("clone_nil_service_config", func(t *testing.T) {
+ var service *ServiceConfig
+ cloned := service.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_empty_service_config", func(t *testing.T) {
+ service := &ServiceConfig{}
+ cloned := service.Clone()
+ assert.NotNil(t, cloned)
+ assert.NotSame(t, service, cloned)
+ })
+
+ t.Run("clone_service_config_with_maps", func(t *testing.T) {
+ service := &ServiceConfig{
+ Interface: "com.test.Service",
+ RCProtocolsMap: map[string]*ProtocolConfig{
+ "proto1": {Name: "tri", Port: "20880"},
+ "proto2": {Name: "dubbo", Port: "20881"},
+ },
+ RCRegistriesMap: map[string]*RegistryConfig{
+ "reg1": {Protocol: "zookeeper", Address:
"localhost:2181"},
+ "reg2": {Protocol: "nacos", Address:
"localhost:8848"},
+ },
+ }
+ cloned := service.Clone()
+ assert.Equal(t, 2, len(cloned.RCProtocolsMap))
+ assert.Equal(t, 2, len(cloned.RCRegistriesMap))
+ assert.NotSame(t, service.RCProtocolsMap, cloned.RCProtocolsMap)
+ assert.NotSame(t, service.RCRegistriesMap,
cloned.RCRegistriesMap)
+ })
+}
+
+// TestDefaultServiceConfig tests DefaultServiceConfig function
+func TestDefaultServiceConfig(t *testing.T) {
+ t.Run("default_service_config", func(t *testing.T) {
+ service := DefaultServiceConfig()
+ assert.NotNil(t, service)
+ assert.NotNil(t, service.Methods)
+ assert.NotNil(t, service.Params)
+ assert.NotNil(t, service.RCProtocolsMap)
+ assert.NotNil(t, service.RCRegistriesMap)
+ assert.Equal(t, 0, len(service.Methods))
+ assert.Equal(t, 0, len(service.Params))
+ })
+}
+
+// TestServiceConfigFields tests individual fields of ServiceConfig
+func TestServiceConfigFields(t *testing.T) {
+ t.Run("service_config_interface", func(t *testing.T) {
+ service := &ServiceConfig{
+ Interface: "com.test.Service",
+ }
+ assert.Equal(t, "com.test.Service", service.Interface)
+ })
+
+ t.Run("service_config_version", func(t *testing.T) {
+ service := &ServiceConfig{
+ Version: "2.0.0",
+ }
+ assert.Equal(t, "2.0.0", service.Version)
+ })
+
+ t.Run("service_config_group", func(t *testing.T) {
+ service := &ServiceConfig{
+ Group: "production",
+ }
+ assert.Equal(t, "production", service.Group)
+ })
+
+ t.Run("service_config_cluster", func(t *testing.T) {
+ service := &ServiceConfig{
+ Cluster: "forking",
+ }
+ assert.Equal(t, "forking", service.Cluster)
+ })
+
+ t.Run("service_config_loadbalance", func(t *testing.T) {
+ service := &ServiceConfig{
+ Loadbalance: "leastactive",
+ }
+ assert.Equal(t, "leastactive", service.Loadbalance)
+ })
+
+ t.Run("service_config_weight", func(t *testing.T) {
+ service := &ServiceConfig{
+ Weight: 200,
+ }
+ assert.Equal(t, int64(200), service.Weight)
+ })
+
+ t.Run("service_config_not_register", func(t *testing.T) {
+ service := &ServiceConfig{
+ NotRegister: true,
+ }
+ assert.True(t, service.NotRegister)
+ })
+
+ t.Run("service_config_protocol_ids", func(t *testing.T) {
+ service := &ServiceConfig{
+ ProtocolIDs: []string{"proto1", "proto2"},
+ }
+ assert.Equal(t, 2, len(service.ProtocolIDs))
+ })
+
+ t.Run("service_config_registry_ids", func(t *testing.T) {
+ service := &ServiceConfig{
+ RegistryIDs: []string{"reg1"},
+ }
+ assert.Equal(t, 1, len(service.RegistryIDs))
+ })
+}
+
+// TestServiceOptionFunc tests the ServiceOption function type
+func TestServiceOptionFunc(t *testing.T) {
+ t.Run("apply_service_option", func(t *testing.T) {
+ service := &ServiceConfig{}
+ opt := func(cfg *ServiceConfig) {
+ cfg.Interface = "com.test.Service"
+ cfg.Version = "1.0.0"
+ }
+ opt(service)
+ assert.Equal(t, "com.test.Service", service.Interface)
+ assert.Equal(t, "1.0.0", service.Version)
+ })
+}
+func TestProviderConfigClone(t *testing.T) {
+ t.Run("clone_full_provider_config", func(t *testing.T) {
+ provider := &ProviderConfig{
+ Filter: "echo",
+ Register: true,
+ RegistryIDs: []string{"reg1", "reg2"},
+ ProtocolIDs: []string{"proto1"},
+ TracingKey: "jaeger",
+ ProxyFactory: "default",
+ AdaptiveService: true,
+ AdaptiveServiceVerbose: true,
+ ConfigType: map[string]string{"key":
"value"},
+ Services: map[string]*ServiceConfig{
+ "service1": {Interface: "com.test.Service1"},
+ },
+ ServiceConfig: ServiceConfig{
+ Interface: "com.test.BaseService",
+ Group: "test",
+ Version: "1.0.0",
+ },
+ }
+
+ cloned := provider.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, provider.Filter, cloned.Filter)
+ assert.Equal(t, provider.Register, cloned.Register)
+ assert.NotSame(t, provider, cloned)
+ assert.NotSame(t, provider.Services, cloned.Services)
+
+ // Verify RegistryIDs is a true deep copy by mutating the clone
+ assert.Equal(t, len(provider.RegistryIDs),
len(cloned.RegistryIDs))
+ assert.Equal(t, provider.RegistryIDs, cloned.RegistryIDs)
+ if len(cloned.RegistryIDs) > 0 {
+ originalValue := cloned.RegistryIDs[0]
+ cloned.RegistryIDs[0] = "modified"
+ assert.NotEqual(t, provider.RegistryIDs[0],
cloned.RegistryIDs[0])
+ cloned.RegistryIDs[0] = originalValue
+ }
+ cloned.RegistryIDs = append(cloned.RegistryIDs, "new_registry")
+ assert.NotEqual(t, len(provider.RegistryIDs),
len(cloned.RegistryIDs))
+
+ // Verify ProtocolIDs is a true deep copy by mutating the clone
+ assert.Equal(t, len(provider.ProtocolIDs),
len(cloned.ProtocolIDs))
+ assert.Equal(t, provider.ProtocolIDs, cloned.ProtocolIDs)
+ if len(cloned.ProtocolIDs) > 0 {
+ originalValue := cloned.ProtocolIDs[0]
+ cloned.ProtocolIDs[0] = "modified"
+ assert.NotEqual(t, provider.ProtocolIDs[0],
cloned.ProtocolIDs[0])
+ cloned.ProtocolIDs[0] = originalValue
+ }
+ cloned.ProtocolIDs = append(cloned.ProtocolIDs, "new_protocol")
+ assert.NotEqual(t, len(provider.ProtocolIDs),
len(cloned.ProtocolIDs))
Review Comment:
Similar to the RegistryIDs test above, this test mutates the cloned slice
element and restores it (lines 1530-1533), then tests appending. The
restoration makes the element mutation test ineffective for verifying deep copy
behavior. The test should either not restore the value or use a different
approach to verify deep copying.
##########
global/config_test.go:
##########
@@ -319,3 +319,1744 @@ func CheckCompleteInequality(t *testing.T, origin any,
clone any) {
}
}
}
+func TestReferenceConfigGetOptions(t *testing.T) {
+ t.Run("full_reference_config", func(t *testing.T) {
+ ref := &ReferenceConfig{
+ InterfaceName: "com.test.Service",
+ URL: "127.0.0.1:20880",
+ Filter: "echo",
+ Protocol: "dubbo",
+ Cluster: "failover",
+ Loadbalance: "random",
+ Retries: "3",
+ Group: "test",
+ Version: "1.0.0",
+ Serialization: "hessian2",
+ ProvidedBy: "provider",
+ Async: true,
+ Generic: "true",
+ Sticky: true,
+ RequestTimeout: "5s",
+ TracingKey: "jaeger",
+ MeshProviderPort: 8080,
+ KeepAliveInterval: "1m",
+ KeepAliveTimeout: "30s",
+ Params: map[string]string{
+ "key": "value",
+ },
+ Check: func() *bool { b := true; return &b }(),
+ RegistryIDs: []string{"reg1", "reg2"},
+ MethodsConfig: []*MethodConfig{
+ {Name: "method1"},
+ },
+ ProtocolClientConfig: DefaultClientProtocolConfig(),
+ }
+
+ opts := ref.GetOptions()
+ assert.NotNil(t, opts, "opts should not be nil")
+ assert.True(t, len(opts) > 0, "opts should have items")
+ })
+
+ t.Run("empty_reference_config", func(t *testing.T) {
+ emptyRef := &ReferenceConfig{}
+ emptyOpts := emptyRef.GetOptions()
+ // An empty config will return nil from GetOptions since all
fields are empty
+ if emptyOpts != nil {
+ assert.Equal(t, 0, len(emptyOpts), "empty ref config
should have no options")
+ }
+ })
+
+ t.Run("nil_reference_config_clone", func(t *testing.T) {
+ var nilRef *ReferenceConfig
+ cloned := nilRef.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("reference_config_with_retries_parsing", func(t *testing.T) {
+ ref := &ReferenceConfig{
+ Retries: "5",
+ }
+ opts := ref.GetOptions()
+ assert.NotNil(t, opts)
+ // Verify that a valid retries value produces an option
+ assert.Greater(t, len(opts), 0, "should have at least one
option from Retries")
+ // Verify retries option is present by checking that we have
options
+ hasRetriesOption := false
+ for _, opt := range opts {
+ // The option function should be WithReference_Retries
+ if opt != nil {
+ hasRetriesOption = true
+ break
+ }
+ }
+ assert.True(t, hasRetriesOption, "should contain a
retries-related option when Retries is a valid integer")
+ })
+
+ t.Run("reference_config_with_invalid_retries", func(t *testing.T) {
+ ref := &ReferenceConfig{
+ Retries: "invalid",
+ }
+ opts := ref.GetOptions()
+ // Invalid retries should not be added to options
+ // This is expected behavior - invalid values are silently
skipped
+ // Verify the returned options do not contain a retries option
+ // by confirming the invalid string is not converted
+
+ // GetOptions returns nil (or empty slice) when no options are
present
+ // Since Retries is the only field and it's invalid, no options
should be produced
+ if opts != nil {
+ // If opts is returned as a slice, it should be empty
since Retries is invalid
+ assert.Equal(t, 0, len(opts), "invalid retries value
should not produce any options")
+ }
+ // The fact that invalid retries is not in opts confirms it was
rejected
+ t.Logf("Invalid retries value was correctly skipped (opts=%v)",
opts)
+ })
+}
+
+// TestReferenceConfigOptions tests the option functions
+func TestReferenceConfigOptions(t *testing.T) {
+ t.Run("WithReference_InterfaceName", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_InterfaceName("com.test.Service")
+ opt(ref)
+ assert.Equal(t, "com.test.Service", ref.InterfaceName)
+ })
+
+ t.Run("WithReference_Check_true", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Check(true)
+ opt(ref)
+ assert.NotNil(t, ref.Check)
+ assert.True(t, *ref.Check)
+ })
+
+ t.Run("WithReference_Check_false", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Check(false)
+ opt(ref)
+ assert.NotNil(t, ref.Check)
+ assert.False(t, *ref.Check)
+ })
+
+ t.Run("WithReference_URL", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_URL("127.0.0.1:20880")
+ opt(ref)
+ assert.Equal(t, "127.0.0.1:20880", ref.URL)
+ })
+
+ t.Run("WithReference_Filter", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Filter("echo")
+ opt(ref)
+ assert.Equal(t, "echo", ref.Filter)
+ })
+
+ t.Run("WithReference_Protocol", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Protocol("tri")
+ opt(ref)
+ assert.Equal(t, "tri", ref.Protocol)
+ })
+
+ t.Run("WithReference_RegistryIDs", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_RegistryIDs([]string{"reg1", "reg2"})
+ opt(ref)
+ assert.Equal(t, 2, len(ref.RegistryIDs))
+ assert.Equal(t, "reg1", ref.RegistryIDs[0])
+ assert.Equal(t, "reg2", ref.RegistryIDs[1])
+ })
+
+ t.Run("WithReference_RegistryIDs_empty", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_RegistryIDs([]string{})
+ opt(ref)
+ assert.Equal(t, 0, len(ref.RegistryIDs))
+ })
+
+ t.Run("WithReference_Cluster", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Cluster("failover")
+ opt(ref)
+ assert.Equal(t, "failover", ref.Cluster)
+ })
+
+ t.Run("WithReference_LoadBalance", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_LoadBalance("random")
+ opt(ref)
+ assert.Equal(t, "random", ref.Loadbalance)
+ })
+
+ t.Run("WithReference_Retries", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Retries(3)
+ opt(ref)
+ assert.Equal(t, "3", ref.Retries)
+ })
+
+ t.Run("WithReference_Group", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Group("test")
+ opt(ref)
+ assert.Equal(t, "test", ref.Group)
+ })
+
+ t.Run("WithReference_Version", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Version("1.0.0")
+ opt(ref)
+ assert.Equal(t, "1.0.0", ref.Version)
+ })
+
+ t.Run("WithReference_Serialization", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Serialization("hessian2")
+ opt(ref)
+ assert.Equal(t, "hessian2", ref.Serialization)
+ })
+
+ t.Run("WithReference_ProviderBy", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_ProviderBy("provider")
+ opt(ref)
+ assert.Equal(t, "provider", ref.ProvidedBy)
+ })
+
+ t.Run("WithReference_Async_true", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Async(true)
+ opt(ref)
+ assert.True(t, ref.Async)
+ })
+
+ t.Run("WithReference_Async_false", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Async(false)
+ opt(ref)
+ assert.False(t, ref.Async)
+ })
+
+ t.Run("WithReference_Params", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ params := map[string]string{"key": "value", "key2": "value2"}
+ opt := WithReference_Params(params)
+ opt(ref)
+ assert.Equal(t, "value", ref.Params["key"])
+ assert.Equal(t, "value2", ref.Params["key2"])
+ })
+
+ t.Run("WithReference_Generic", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Generic("true")
+ opt(ref)
+ assert.Equal(t, "true", ref.Generic)
+ })
+
+ t.Run("WithReference_Sticky", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Sticky(true)
+ opt(ref)
+ assert.True(t, ref.Sticky)
+ })
+
+ t.Run("WithReference_RequestTimeout", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_RequestTimeout("5s")
+ opt(ref)
+ assert.Equal(t, "5s", ref.RequestTimeout)
+ })
+
+ t.Run("WithReference_Force", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Force(true)
+ opt(ref)
+ assert.True(t, ref.ForceTag)
+ })
+
+ t.Run("WithReference_TracingKey", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_TracingKey("jaeger")
+ opt(ref)
+ assert.Equal(t, "jaeger", ref.TracingKey)
+ })
+
+ t.Run("WithReference_MeshProviderPort", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_MeshProviderPort(8080)
+ opt(ref)
+ assert.Equal(t, 8080, ref.MeshProviderPort)
+ })
+
+ t.Run("WithReference_KeepAliveInterval", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_KeepAliveInterval("1m")
+ opt(ref)
+ assert.Equal(t, "1m", ref.KeepAliveInterval)
+ })
+
+ t.Run("WithReference_KeepAliveTimeout", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_KeepAliveTimeout("30s")
+ opt(ref)
+ assert.Equal(t, "30s", ref.KeepAliveTimeout)
+ })
+
+ t.Run("WithReference_ProtocolClientConfig", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ pcc := DefaultClientProtocolConfig()
+ opt := WithReference_ProtocolClientConfig(pcc)
+ opt(ref)
+ assert.NotNil(t, ref.ProtocolClientConfig)
+ })
+}
+func TestRegistryConfigUseAsMetadataReport(t *testing.T) {
+ t.Run("empty_use_as_meta_report_defaults_to_true", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: ""}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.True(t, result)
+ })
+
+ t.Run("true_string", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "true"}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.True(t, result)
+ })
+
+ t.Run("false_string", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "false"}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.False(t, result)
+ })
+
+ t.Run("TRUE_uppercase", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "TRUE"}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.True(t, result)
+ })
+
+ t.Run("FALSE_uppercase", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "FALSE"}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.False(t, result)
+ })
+
+ t.Run("invalid_use_as_meta_report", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "invalid"}
+ result, err := reg.UseAsMetadataReport()
+ assert.NotNil(t, err)
+ assert.False(t, result)
+ })
+
+ t.Run("1_as_true", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "1"}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.True(t, result)
+ })
+
+ t.Run("0_as_false", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "0"}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.False(t, result)
+ })
+}
+
+// TestRegistryConfigClone tests the Clone method of RegistryConfig
+func TestRegistryConfigClone(t *testing.T) {
+ t.Run("clone_full_registry_config", func(t *testing.T) {
+ reg := &RegistryConfig{
+ Protocol: "zookeeper",
+ Timeout: "5s",
+ Group: "test",
+ Namespace: "ns",
+ TTL: "15m",
+ Address: "localhost:2181",
+ Username: "user",
+ Password: "pass",
+ Simplified: true,
+ Preferred: true,
+ Zone: "zone1",
+ Weight: 100,
+ UseAsMetaReport: "true",
+ UseAsConfigCenter: "true",
+ RegistryType: "nacos",
+ Params: map[string]string{
+ "key1": "value1",
+ "key2": "value2",
+ },
+ }
+ cloned := reg.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, reg.Protocol, cloned.Protocol)
+ assert.Equal(t, reg.Timeout, cloned.Timeout)
+ assert.Equal(t, reg.Group, cloned.Group)
+ assert.Equal(t, reg.Namespace, cloned.Namespace)
+ assert.Equal(t, reg.TTL, cloned.TTL)
+ assert.Equal(t, reg.Address, cloned.Address)
+ assert.Equal(t, reg.Username, cloned.Username)
+ assert.Equal(t, reg.Password, cloned.Password)
+ assert.Equal(t, reg.Simplified, cloned.Simplified)
+ assert.Equal(t, reg.Preferred, cloned.Preferred)
+ assert.Equal(t, reg.Zone, cloned.Zone)
+ assert.Equal(t, reg.Weight, cloned.Weight)
+ assert.Equal(t, reg.UseAsMetaReport, cloned.UseAsMetaReport)
+ assert.Equal(t, reg.UseAsConfigCenter, cloned.UseAsConfigCenter)
+ assert.NotSame(t, reg, cloned)
+ assert.NotSame(t, reg.Params, cloned.Params)
+ assert.Equal(t, "value1", cloned.Params["key1"])
+ assert.Equal(t, "value2", cloned.Params["key2"])
+ })
+
+ t.Run("clone_nil_registry_config", func(t *testing.T) {
+ var reg *RegistryConfig
+ cloned := reg.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_empty_registry_config", func(t *testing.T) {
+ reg := &RegistryConfig{}
+ cloned := reg.Clone()
+ assert.NotNil(t, cloned)
+ assert.NotSame(t, reg, cloned)
+ })
+
+ t.Run("clone_with_empty_params", func(t *testing.T) {
+ reg := &RegistryConfig{
+ Protocol: "nacos",
+ Params: make(map[string]string),
+ }
+ cloned := reg.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, 0, len(cloned.Params))
+ assert.NotSame(t, reg.Params, cloned.Params)
+ })
+}
+
+// TestDefaultRegistryConfig tests DefaultRegistryConfig function
+func TestDefaultRegistryConfig(t *testing.T) {
+ t.Run("default_registry_config", func(t *testing.T) {
+ reg := DefaultRegistryConfig()
+ assert.NotNil(t, reg)
+ assert.Equal(t, "true", reg.UseAsMetaReport)
+ assert.Equal(t, "true", reg.UseAsConfigCenter)
+ assert.Equal(t, "5s", reg.Timeout)
+ assert.Equal(t, "15m", reg.TTL)
+ })
+}
+
+// TestDefaultRegistriesConfig tests DefaultRegistriesConfig function
+func TestDefaultRegistriesConfig(t *testing.T) {
+ t.Run("default_registries_config", func(t *testing.T) {
+ regs := DefaultRegistriesConfig()
+ assert.NotNil(t, regs)
+ assert.Equal(t, 0, len(regs))
+ })
+}
+
+// TestCloneRegistriesConfig tests CloneRegistriesConfig function
+func TestCloneRegistriesConfig(t *testing.T) {
+ t.Run("clone_multiple_registries", func(t *testing.T) {
+ regs := map[string]*RegistryConfig{
+ "reg1": {
+ Protocol: "zookeeper",
+ Address: "localhost:2181",
+ Params: map[string]string{
+ "key": "value",
+ },
+ },
+ "reg2": {
+ Protocol: "nacos",
+ Address: "localhost:8848",
+ Params: map[string]string{
+ "key2": "value2",
+ },
+ },
+ }
+ cloned := CloneRegistriesConfig(regs)
+ assert.Equal(t, 2, len(cloned))
+ assert.Equal(t, "zookeeper", cloned["reg1"].Protocol)
+ assert.Equal(t, "nacos", cloned["reg2"].Protocol)
+ assert.NotSame(t, regs["reg1"], cloned["reg1"])
+ assert.NotSame(t, regs["reg2"], cloned["reg2"])
+ assert.Equal(t, "value", cloned["reg1"].Params["key"])
+ assert.Equal(t, "value2", cloned["reg2"].Params["key2"])
+ })
+
+ t.Run("clone_nil_registries_config", func(t *testing.T) {
+ var regs map[string]*RegistryConfig
+ cloned := CloneRegistriesConfig(regs)
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_empty_registries_config", func(t *testing.T) {
+ regs := make(map[string]*RegistryConfig)
+ cloned := CloneRegistriesConfig(regs)
+ assert.NotNil(t, cloned)
+ assert.Equal(t, 0, len(cloned))
+ assert.NotSame(t, regs, cloned)
+ })
+
+ t.Run("clone_single_registry", func(t *testing.T) {
+ regs := map[string]*RegistryConfig{
+ "reg1": {
+ Protocol: "etcdv3",
+ Timeout: "10s",
+ Weight: 50,
+ Preferred: true,
+ },
+ }
+ cloned := CloneRegistriesConfig(regs)
+ assert.Equal(t, 1, len(cloned))
+ assert.Equal(t, "etcdv3", cloned["reg1"].Protocol)
+ assert.Equal(t, "10s", cloned["reg1"].Timeout)
+ assert.Equal(t, int64(50), cloned["reg1"].Weight)
+ assert.True(t, cloned["reg1"].Preferred)
+ })
+}
+func TestRouterConfigClone(t *testing.T) {
+ t.Run("clone_full_router_config", func(t *testing.T) {
+ router := &RouterConfig{
+ Scope: "service",
+ Key: "com.test.Service",
+ Priority: 10,
+ ScriptType: "javascript",
+ Script: "1==1",
+ Force: func() *bool {
+ b := true
+ return &b
+ }(),
+ Runtime: func() *bool {
+ b := false
+ return &b
+ }(),
+ Enabled: func() *bool {
+ b := true
+ return &b
+ }(),
+ Valid: func() *bool {
+ b := true
+ return &b
+ }(),
+ Conditions: []string{"condition1", "condition2"},
+ Tags: []Tag{
+ {
+ Name: "tag1",
+ Addresses: []string{"addr1", "addr2"},
+ },
+ {
+ Name: "tag2",
+ Addresses: []string{"addr3"},
+ },
+ },
+ }
+
+ cloned := router.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, router.Scope, cloned.Scope)
+ assert.Equal(t, router.Key, cloned.Key)
+ assert.Equal(t, router.Priority, cloned.Priority)
+ assert.Equal(t, router.ScriptType, cloned.ScriptType)
+ assert.Equal(t, router.Script, cloned.Script)
+ assert.NotSame(t, router, cloned)
+ assert.NotSame(t, router.Conditions, cloned.Conditions)
+ assert.NotSame(t, router.Tags, cloned.Tags)
+ assert.Equal(t, 2, len(cloned.Conditions))
+ assert.Equal(t, 2, len(cloned.Tags))
+ assert.Equal(t, "tag1", cloned.Tags[0].Name)
+ assert.Equal(t, "tag2", cloned.Tags[1].Name)
+ assert.Equal(t, 2, len(cloned.Tags[0].Addresses))
+ assert.Equal(t, 1, len(cloned.Tags[1].Addresses))
+ })
+
+ t.Run("clone_nil_router_config", func(t *testing.T) {
+ var router *RouterConfig
+ cloned := router.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_empty_router_config", func(t *testing.T) {
+ router := &RouterConfig{}
+ cloned := router.Clone()
+ assert.NotNil(t, cloned)
+ assert.NotSame(t, router, cloned)
+ })
+
+ t.Run("clone_router_config_with_nil_pointers", func(t *testing.T) {
+ router := &RouterConfig{
+ Scope: "service",
+ Key: "com.test.Service",
+ Force: nil,
+ Runtime: nil,
+ }
+ cloned := router.Clone()
+ assert.NotNil(t, cloned)
+ assert.Nil(t, cloned.Force)
+ assert.Nil(t, cloned.Runtime)
+ })
+
+ t.Run("clone_router_config_preserves_pointer_values", func(t
*testing.T) {
+ forceTrue := true
+ runtimeFalse := false
+ router := &RouterConfig{
+ Scope: "service",
+ Key: "test",
+ Force: &forceTrue,
+ Runtime: &runtimeFalse,
+ }
+ cloned := router.Clone()
+ assert.NotNil(t, cloned.Force)
+ assert.NotNil(t, cloned.Runtime)
+ assert.True(t, *cloned.Force)
+ assert.False(t, *cloned.Runtime)
+ assert.NotSame(t, router.Force, cloned.Force)
+ assert.NotSame(t, router.Runtime, cloned.Runtime)
+ })
+}
+
+// TestDefaultRouterConfig tests DefaultRouterConfig function
+func TestDefaultRouterConfig(t *testing.T) {
+ t.Run("default_router_config", func(t *testing.T) {
+ router := DefaultRouterConfig()
+ assert.NotNil(t, router)
+ assert.Equal(t, 0, len(router.Conditions))
+ assert.Equal(t, 0, len(router.Tags))
+ })
+}
+
+// TestTagStructure tests Tag structure and cloning
+func TestTagStructure(t *testing.T) {
+ t.Run("tag_with_addresses", func(t *testing.T) {
+ tag := Tag{
+ Name: "test",
+ Addresses: []string{"addr1", "addr2"},
+ }
+ assert.Equal(t, "test", tag.Name)
+ assert.Equal(t, 2, len(tag.Addresses))
+ })
+
+ t.Run("tag_with_empty_addresses", func(t *testing.T) {
+ tag := Tag{
+ Name: "test",
+ Addresses: []string{},
+ }
+ assert.Equal(t, 0, len(tag.Addresses))
+ })
+}
+
+// TestRouterConfigFields tests individual fields of RouterConfig
+func TestRouterConfigFields(t *testing.T) {
+ t.Run("router_config_scope", func(t *testing.T) {
+ router := &RouterConfig{
+ Scope: "application",
+ }
+ assert.Equal(t, "application", router.Scope)
+ })
+
+ t.Run("router_config_priority", func(t *testing.T) {
+ router := &RouterConfig{
+ Priority: 100,
+ }
+ assert.Equal(t, 100, router.Priority)
+ })
+
+ t.Run("router_config_script_type", func(t *testing.T) {
+ router := &RouterConfig{
+ ScriptType: "groovy",
+ Script: "1 == 1",
+ }
+ assert.Equal(t, "groovy", router.ScriptType)
+ assert.Equal(t, "1 == 1", router.Script)
+ })
+
+ t.Run("router_config_conditions_multiple", func(t *testing.T) {
+ router := &RouterConfig{
+ Conditions: []string{"cond1", "cond2", "cond3"},
+ }
+ assert.Equal(t, 3, len(router.Conditions))
+ assert.Equal(t, "cond1", router.Conditions[0])
+ assert.Equal(t, "cond3", router.Conditions[2])
+ })
+}
+func TestProtocolConfigClone(t *testing.T) {
+ t.Run("clone_full_protocol_config", func(t *testing.T) {
+ proto := &ProtocolConfig{
+ Name: "tri",
+ Ip: "127.0.0.1",
+ Port: "20880",
+ MaxServerSendMsgSize: "1mb",
+ MaxServerRecvMsgSize: "4mb",
+ TripleConfig: &TripleConfig{
+ MaxServerSendMsgSize: "2mb",
+ MaxServerRecvMsgSize: "4mb",
+ KeepAliveInterval: "1m",
+ KeepAliveTimeout: "30s",
+ Http3: DefaultHttp3Config(),
+ },
+ Params: map[string]string{
+ "key1": "value1",
+ "key2": "value2",
+ },
+ }
+
+ cloned := proto.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, proto.Name, cloned.Name)
+ assert.Equal(t, proto.Ip, cloned.Ip)
+ assert.Equal(t, proto.Port, cloned.Port)
+ assert.Equal(t, proto.MaxServerSendMsgSize,
cloned.MaxServerSendMsgSize)
+ assert.Equal(t, proto.MaxServerRecvMsgSize,
cloned.MaxServerRecvMsgSize)
+ assert.NotSame(t, proto, cloned)
+ assert.NotSame(t, proto.TripleConfig, cloned.TripleConfig)
+ assert.NotNil(t, cloned.TripleConfig)
+ })
+
+ t.Run("clone_nil_protocol_config", func(t *testing.T) {
+ var proto *ProtocolConfig
+ cloned := proto.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_protocol_config_with_nil_triple_config", func(t
*testing.T) {
+ proto := &ProtocolConfig{
+ Name: "dubbo",
+ Port: "20880",
+ }
+ cloned := proto.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, "dubbo", cloned.Name)
+ })
+
+ t.Run("clone_protocol_config_preserves_all_fields", func(t *testing.T) {
+ proto := &ProtocolConfig{
+ Name: "http",
+ Ip: "192.168.1.1",
+ Port: "8080",
+ MaxServerSendMsgSize: "10mb",
+ MaxServerRecvMsgSize: "10mb",
+ }
+ cloned := proto.Clone()
+ assert.Equal(t, "http", cloned.Name)
+ assert.Equal(t, "192.168.1.1", cloned.Ip)
+ assert.Equal(t, "8080", cloned.Port)
+ assert.Equal(t, "10mb", cloned.MaxServerSendMsgSize)
+ assert.Equal(t, "10mb", cloned.MaxServerRecvMsgSize)
+ })
+}
+
+// TestDefaultProtocolConfig tests DefaultProtocolConfig function
+func TestDefaultProtocolConfig(t *testing.T) {
+ t.Run("default_protocol_config", func(t *testing.T) {
+ proto := DefaultProtocolConfig()
+ assert.NotNil(t, proto)
+ assert.NotEmpty(t, proto.Name)
+ assert.NotEmpty(t, proto.Port)
+ assert.NotNil(t, proto.TripleConfig)
+ })
+}
+
+// TestProtocolConfigFields tests individual fields of ProtocolConfig
+func TestProtocolConfigFields(t *testing.T) {
+ t.Run("protocol_config_name", func(t *testing.T) {
+ proto := &ProtocolConfig{Name: "dubbo"}
+ assert.Equal(t, "dubbo", proto.Name)
+ })
+
+ t.Run("protocol_config_ip", func(t *testing.T) {
+ proto := &ProtocolConfig{Ip: "10.0.0.1"}
+ assert.Equal(t, "10.0.0.1", proto.Ip)
+ })
+
+ t.Run("protocol_config_port", func(t *testing.T) {
+ proto := &ProtocolConfig{Port: "9090"}
+ assert.Equal(t, "9090", proto.Port)
+ })
+
+ t.Run("protocol_config_with_params", func(t *testing.T) {
+ params := map[string]string{
+ "param1": "value1",
+ "param2": "value2",
+ }
+ proto := &ProtocolConfig{
+ Name: "tri",
+ Params: params,
+ }
+ assert.NotNil(t, proto.Params)
+ })
+
+ t.Run("protocol_config_with_triple_config", func(t *testing.T) {
+ tripleConfig := &TripleConfig{
+ KeepAliveInterval: "2m",
+ KeepAliveTimeout: "60s",
+ }
+ proto := &ProtocolConfig{
+ Name: "tri",
+ TripleConfig: tripleConfig,
+ }
+ assert.NotNil(t, proto.TripleConfig)
+ assert.Equal(t, "2m", proto.TripleConfig.KeepAliveInterval)
+ assert.Equal(t, "60s", proto.TripleConfig.KeepAliveTimeout)
+ })
+}
+
+// TestTripleConfigClone tests the Clone method of TripleConfig
+func TestTripleConfigClone(t *testing.T) {
+ t.Run("clone_full_triple_config", func(t *testing.T) {
+ triple := &TripleConfig{
+ MaxServerSendMsgSize: "5mb",
+ MaxServerRecvMsgSize: "5mb",
+ KeepAliveInterval: "3m",
+ KeepAliveTimeout: "45s",
+ Http3: DefaultHttp3Config(),
+ }
+ cloned := triple.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, triple.MaxServerSendMsgSize,
cloned.MaxServerSendMsgSize)
+ assert.Equal(t, triple.MaxServerRecvMsgSize,
cloned.MaxServerRecvMsgSize)
+ assert.Equal(t, triple.KeepAliveInterval,
cloned.KeepAliveInterval)
+ assert.Equal(t, triple.KeepAliveTimeout,
cloned.KeepAliveTimeout)
+ assert.NotSame(t, triple, cloned)
+ assert.NotSame(t, triple.Http3, cloned.Http3)
+ })
+
+ t.Run("clone_nil_triple_config", func(t *testing.T) {
+ var triple *TripleConfig
+ cloned := triple.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_triple_config_with_nil_http3", func(t *testing.T) {
+ triple := &TripleConfig{
+ MaxServerSendMsgSize: "1mb",
+ }
+ cloned := triple.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, "1mb", cloned.MaxServerSendMsgSize)
+ })
+}
+
+// TestDefaultTripleConfig tests DefaultTripleConfig function
+func TestDefaultTripleConfig(t *testing.T) {
+ t.Run("default_triple_config", func(t *testing.T) {
+ triple := DefaultTripleConfig()
+ assert.NotNil(t, triple)
+ assert.NotNil(t, triple.Http3)
+ })
+}
+
+// TestHttp3ConfigClone tests the Clone method of Http3Config
+func TestHttp3ConfigClone(t *testing.T) {
+ t.Run("clone_http3_config", func(t *testing.T) {
+ http3 := &Http3Config{
+ Enable: true,
+ Negotiation: false,
+ }
+ cloned := http3.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, http3.Enable, cloned.Enable)
+ assert.Equal(t, http3.Negotiation, cloned.Negotiation)
+ })
+
+ t.Run("clone_nil_http3_config", func(t *testing.T) {
+ var http3 *Http3Config
+ cloned := http3.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_http3_config_with_defaults", func(t *testing.T) {
+ http3 := DefaultHttp3Config()
+ cloned := http3.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, http3.Enable, cloned.Enable)
+ assert.Equal(t, http3.Negotiation, cloned.Negotiation)
+ })
+}
+
+// TestDefaultHttp3Config tests DefaultHttp3Config function
+func TestDefaultHttp3Config(t *testing.T) {
+ t.Run("default_http3_config", func(t *testing.T) {
+ http3 := DefaultHttp3Config()
+ assert.NotNil(t, http3)
+ })
+}
+func TestConsumerConfigClone(t *testing.T) {
+ t.Run("clone_full_consumer_config", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ Filter: "echo",
+ Protocol: "dubbo",
+ RequestTimeout: "5s",
+ ProxyFactory: "default",
+ Check: true,
+ AdaptiveService: true,
+ TracingKey: "jaeger",
+ MeshEnabled: true,
+ MaxWaitTimeForServiceDiscovery: "5s",
+ RegistryIDs: []string{"reg1",
"reg2"},
+ References: map[string]*ReferenceConfig{
+ "ref1": {
+ InterfaceName: "com.test.Service1",
+ },
+ "ref2": {
+ InterfaceName: "com.test.Service2",
+ },
+ },
+ }
+
+ cloned := consumer.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, consumer.Filter, cloned.Filter)
+ assert.Equal(t, consumer.Protocol, cloned.Protocol)
+ assert.Equal(t, consumer.RequestTimeout, cloned.RequestTimeout)
+ assert.Equal(t, consumer.Check, cloned.Check)
+ assert.Equal(t, consumer.AdaptiveService,
cloned.AdaptiveService)
+ assert.NotSame(t, consumer, cloned)
+ assert.NotSame(t, consumer.References, cloned.References)
+ assert.Equal(t, 2, len(cloned.References))
+ assert.Equal(t, "com.test.Service1",
cloned.References["ref1"].InterfaceName)
+ })
+
+ t.Run("clone_nil_consumer_config", func(t *testing.T) {
+ var consumer *ConsumerConfig
+ cloned := consumer.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_consumer_config_with_empty_references", func(t *testing.T)
{
+ consumer := &ConsumerConfig{
+ Filter: "echo",
+ }
+ cloned := consumer.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, "echo", cloned.Filter)
+ assert.NotSame(t, consumer, cloned)
+ })
+}
+
+// TestDefaultConsumerConfig tests DefaultConsumerConfig function
+func TestDefaultConsumerConfig(t *testing.T) {
+ t.Run("default_consumer_config", func(t *testing.T) {
+ consumer := DefaultConsumerConfig()
+ assert.NotNil(t, consumer)
+ assert.True(t, consumer.Check)
+ assert.NotNil(t, consumer.References)
+ assert.Equal(t, 0, len(consumer.References))
+ })
+}
+
+// TestConsumerConfigFields tests individual fields of ConsumerConfig
+func TestConsumerConfigFields(t *testing.T) {
+ t.Run("consumer_config_filter", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ Filter: "echo",
+ }
+ assert.Equal(t, "echo", consumer.Filter)
+ })
+
+ t.Run("consumer_config_protocol", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ Protocol: "tri",
+ }
+ assert.Equal(t, "tri", consumer.Protocol)
+ })
+
+ t.Run("consumer_config_timeout", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ RequestTimeout: "10s",
+ }
+ assert.Equal(t, "10s", consumer.RequestTimeout)
+ })
+
+ t.Run("consumer_config_check", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ Check: false,
+ }
+ assert.False(t, consumer.Check)
+ })
+
+ t.Run("consumer_config_adaptive_service", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ AdaptiveService: true,
+ }
+ assert.True(t, consumer.AdaptiveService)
+ })
+
+ t.Run("consumer_config_registry_ids", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ RegistryIDs: []string{"reg1", "reg2", "reg3"},
+ }
+ assert.Equal(t, 3, len(consumer.RegistryIDs))
+ })
+
+ t.Run("consumer_config_mesh_enabled", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ MeshEnabled: true,
+ }
+ assert.True(t, consumer.MeshEnabled)
+ })
+}
+func TestServiceConfigClone(t *testing.T) {
+ t.Run("clone_full_service_config", func(t *testing.T) {
+ service := &ServiceConfig{
+ Filter: "echo",
+ Interface: "com.test.Service",
+ Group: "test",
+ Version: "1.0.0",
+ Cluster: "failover",
+ Loadbalance: "random",
+ NotRegister: true,
+ Weight: 100,
+ TracingKey: "jaeger",
+ Auth: "token",
+ Token: "abc123",
+ AccessLog: "true",
+ TpsLimiter: "default",
+ TpsLimitInterval: "1000",
+ TpsLimitRate: "100",
+ TpsLimitStrategy: "default",
+ ExecuteLimit: "10",
+ ExecuteLimitRejectedHandler: "default",
+ ParamSign: "true",
+ Tag: "prod",
+ Warmup: "60",
+ Retries: "3",
+ Serialization: "hessian2",
+ ProtocolIDs: []string{"proto1"},
+ RegistryIDs: []string{"reg1"},
+ Methods: []*MethodConfig{
+ {Name: "method1"},
+ },
+ Params: map[string]string{
+ "key": "value",
+ },
+ RCProtocolsMap: map[string]*ProtocolConfig{
+ "proto1": {Name: "tri"},
+ },
+ RCRegistriesMap: map[string]*RegistryConfig{
+ "reg1": {Protocol: "zookeeper"},
+ },
+ }
+
+ cloned := service.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, service.Filter, cloned.Filter)
+ assert.Equal(t, service.Interface, cloned.Interface)
+ assert.Equal(t, service.Group, cloned.Group)
+ assert.Equal(t, service.Version, cloned.Version)
+ assert.NotSame(t, service, cloned)
+ assert.NotSame(t, service.Params, cloned.Params)
+ assert.Equal(t, "value", cloned.Params["key"])
+ assert.Equal(t, 1, len(cloned.ProtocolIDs))
+ assert.Equal(t, 1, len(cloned.RegistryIDs))
+ })
+
+ t.Run("clone_nil_service_config", func(t *testing.T) {
+ var service *ServiceConfig
+ cloned := service.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_empty_service_config", func(t *testing.T) {
+ service := &ServiceConfig{}
+ cloned := service.Clone()
+ assert.NotNil(t, cloned)
+ assert.NotSame(t, service, cloned)
+ })
+
+ t.Run("clone_service_config_with_maps", func(t *testing.T) {
+ service := &ServiceConfig{
+ Interface: "com.test.Service",
+ RCProtocolsMap: map[string]*ProtocolConfig{
+ "proto1": {Name: "tri", Port: "20880"},
+ "proto2": {Name: "dubbo", Port: "20881"},
+ },
+ RCRegistriesMap: map[string]*RegistryConfig{
+ "reg1": {Protocol: "zookeeper", Address:
"localhost:2181"},
+ "reg2": {Protocol: "nacos", Address:
"localhost:8848"},
+ },
+ }
+ cloned := service.Clone()
+ assert.Equal(t, 2, len(cloned.RCProtocolsMap))
+ assert.Equal(t, 2, len(cloned.RCRegistriesMap))
+ assert.NotSame(t, service.RCProtocolsMap, cloned.RCProtocolsMap)
+ assert.NotSame(t, service.RCRegistriesMap,
cloned.RCRegistriesMap)
+ })
+}
+
+// TestDefaultServiceConfig tests DefaultServiceConfig function
+func TestDefaultServiceConfig(t *testing.T) {
+ t.Run("default_service_config", func(t *testing.T) {
+ service := DefaultServiceConfig()
+ assert.NotNil(t, service)
+ assert.NotNil(t, service.Methods)
+ assert.NotNil(t, service.Params)
+ assert.NotNil(t, service.RCProtocolsMap)
+ assert.NotNil(t, service.RCRegistriesMap)
+ assert.Equal(t, 0, len(service.Methods))
+ assert.Equal(t, 0, len(service.Params))
+ })
+}
+
+// TestServiceConfigFields tests individual fields of ServiceConfig
+func TestServiceConfigFields(t *testing.T) {
+ t.Run("service_config_interface", func(t *testing.T) {
+ service := &ServiceConfig{
+ Interface: "com.test.Service",
+ }
+ assert.Equal(t, "com.test.Service", service.Interface)
+ })
+
+ t.Run("service_config_version", func(t *testing.T) {
+ service := &ServiceConfig{
+ Version: "2.0.0",
+ }
+ assert.Equal(t, "2.0.0", service.Version)
+ })
+
+ t.Run("service_config_group", func(t *testing.T) {
+ service := &ServiceConfig{
+ Group: "production",
+ }
+ assert.Equal(t, "production", service.Group)
+ })
+
+ t.Run("service_config_cluster", func(t *testing.T) {
+ service := &ServiceConfig{
+ Cluster: "forking",
+ }
+ assert.Equal(t, "forking", service.Cluster)
+ })
+
+ t.Run("service_config_loadbalance", func(t *testing.T) {
+ service := &ServiceConfig{
+ Loadbalance: "leastactive",
+ }
+ assert.Equal(t, "leastactive", service.Loadbalance)
+ })
+
+ t.Run("service_config_weight", func(t *testing.T) {
+ service := &ServiceConfig{
+ Weight: 200,
+ }
+ assert.Equal(t, int64(200), service.Weight)
+ })
+
+ t.Run("service_config_not_register", func(t *testing.T) {
+ service := &ServiceConfig{
+ NotRegister: true,
+ }
+ assert.True(t, service.NotRegister)
+ })
+
+ t.Run("service_config_protocol_ids", func(t *testing.T) {
+ service := &ServiceConfig{
+ ProtocolIDs: []string{"proto1", "proto2"},
+ }
+ assert.Equal(t, 2, len(service.ProtocolIDs))
+ })
+
+ t.Run("service_config_registry_ids", func(t *testing.T) {
+ service := &ServiceConfig{
+ RegistryIDs: []string{"reg1"},
+ }
+ assert.Equal(t, 1, len(service.RegistryIDs))
+ })
+}
+
+// TestServiceOptionFunc tests the ServiceOption function type
+func TestServiceOptionFunc(t *testing.T) {
+ t.Run("apply_service_option", func(t *testing.T) {
+ service := &ServiceConfig{}
+ opt := func(cfg *ServiceConfig) {
+ cfg.Interface = "com.test.Service"
+ cfg.Version = "1.0.0"
+ }
+ opt(service)
+ assert.Equal(t, "com.test.Service", service.Interface)
+ assert.Equal(t, "1.0.0", service.Version)
+ })
+}
+func TestProviderConfigClone(t *testing.T) {
+ t.Run("clone_full_provider_config", func(t *testing.T) {
+ provider := &ProviderConfig{
+ Filter: "echo",
+ Register: true,
+ RegistryIDs: []string{"reg1", "reg2"},
+ ProtocolIDs: []string{"proto1"},
+ TracingKey: "jaeger",
+ ProxyFactory: "default",
+ AdaptiveService: true,
+ AdaptiveServiceVerbose: true,
+ ConfigType: map[string]string{"key":
"value"},
+ Services: map[string]*ServiceConfig{
+ "service1": {Interface: "com.test.Service1"},
+ },
+ ServiceConfig: ServiceConfig{
+ Interface: "com.test.BaseService",
+ Group: "test",
+ Version: "1.0.0",
+ },
+ }
+
+ cloned := provider.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, provider.Filter, cloned.Filter)
+ assert.Equal(t, provider.Register, cloned.Register)
+ assert.NotSame(t, provider, cloned)
+ assert.NotSame(t, provider.Services, cloned.Services)
+
+ // Verify RegistryIDs is a true deep copy by mutating the clone
+ assert.Equal(t, len(provider.RegistryIDs),
len(cloned.RegistryIDs))
+ assert.Equal(t, provider.RegistryIDs, cloned.RegistryIDs)
+ if len(cloned.RegistryIDs) > 0 {
+ originalValue := cloned.RegistryIDs[0]
+ cloned.RegistryIDs[0] = "modified"
+ assert.NotEqual(t, provider.RegistryIDs[0],
cloned.RegistryIDs[0])
+ cloned.RegistryIDs[0] = originalValue
+ }
+ cloned.RegistryIDs = append(cloned.RegistryIDs, "new_registry")
+ assert.NotEqual(t, len(provider.RegistryIDs),
len(cloned.RegistryIDs))
Review Comment:
The test mutates the cloned slice element and then restores it (lines
1518-1521), but then tests appending to the slice (line 1523). In Go, slices
share the same underlying array when copied, so the mutation test on line 1520
will fail if the Clone method only does a shallow copy of the slice. However,
the restoration on line 1521 makes this ineffective because by the time we
append on line 1523, we've already restored the original value. The test should
not restore the value if we want to verify deep copying, or should verify the
deep copy differently without mutations that affect both copies.
##########
global/config_test.go:
##########
@@ -319,3 +319,1744 @@ func CheckCompleteInequality(t *testing.T, origin any,
clone any) {
}
}
}
+func TestReferenceConfigGetOptions(t *testing.T) {
+ t.Run("full_reference_config", func(t *testing.T) {
+ ref := &ReferenceConfig{
+ InterfaceName: "com.test.Service",
+ URL: "127.0.0.1:20880",
+ Filter: "echo",
+ Protocol: "dubbo",
+ Cluster: "failover",
+ Loadbalance: "random",
+ Retries: "3",
+ Group: "test",
+ Version: "1.0.0",
+ Serialization: "hessian2",
+ ProvidedBy: "provider",
+ Async: true,
+ Generic: "true",
+ Sticky: true,
+ RequestTimeout: "5s",
+ TracingKey: "jaeger",
+ MeshProviderPort: 8080,
+ KeepAliveInterval: "1m",
+ KeepAliveTimeout: "30s",
+ Params: map[string]string{
+ "key": "value",
+ },
+ Check: func() *bool { b := true; return &b }(),
+ RegistryIDs: []string{"reg1", "reg2"},
+ MethodsConfig: []*MethodConfig{
+ {Name: "method1"},
+ },
+ ProtocolClientConfig: DefaultClientProtocolConfig(),
+ }
+
+ opts := ref.GetOptions()
+ assert.NotNil(t, opts, "opts should not be nil")
+ assert.True(t, len(opts) > 0, "opts should have items")
+ })
+
+ t.Run("empty_reference_config", func(t *testing.T) {
+ emptyRef := &ReferenceConfig{}
+ emptyOpts := emptyRef.GetOptions()
+ // An empty config will return nil from GetOptions since all
fields are empty
+ if emptyOpts != nil {
+ assert.Equal(t, 0, len(emptyOpts), "empty ref config
should have no options")
+ }
+ })
+
+ t.Run("nil_reference_config_clone", func(t *testing.T) {
+ var nilRef *ReferenceConfig
+ cloned := nilRef.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("reference_config_with_retries_parsing", func(t *testing.T) {
+ ref := &ReferenceConfig{
+ Retries: "5",
+ }
+ opts := ref.GetOptions()
+ assert.NotNil(t, opts)
+ // Verify that a valid retries value produces an option
+ assert.Greater(t, len(opts), 0, "should have at least one
option from Retries")
+ // Verify retries option is present by checking that we have
options
+ hasRetriesOption := false
+ for _, opt := range opts {
+ // The option function should be WithReference_Retries
+ if opt != nil {
+ hasRetriesOption = true
+ break
+ }
+ }
+ assert.True(t, hasRetriesOption, "should contain a
retries-related option when Retries is a valid integer")
Review Comment:
The test logic here is checking if any option is not nil, which is always
true for function values in Go. This test doesn't actually verify that a
retries-specific option is present. The check `if opt != nil` for a function
will always be true unless the function itself is nil, which doesn't validate
the retry behavior. Consider checking the actual behavior by applying the
options to a test config and verifying the resulting state.
```suggestion
// Verify that a valid retries value produces at least one
option
assert.Greater(t, len(opts), 0, "should have at least one
option from Retries")
```
##########
global/config_test.go:
##########
@@ -319,3 +319,1744 @@ func CheckCompleteInequality(t *testing.T, origin any,
clone any) {
}
}
}
+func TestReferenceConfigGetOptions(t *testing.T) {
+ t.Run("full_reference_config", func(t *testing.T) {
+ ref := &ReferenceConfig{
+ InterfaceName: "com.test.Service",
+ URL: "127.0.0.1:20880",
+ Filter: "echo",
+ Protocol: "dubbo",
+ Cluster: "failover",
+ Loadbalance: "random",
+ Retries: "3",
+ Group: "test",
+ Version: "1.0.0",
+ Serialization: "hessian2",
+ ProvidedBy: "provider",
+ Async: true,
+ Generic: "true",
+ Sticky: true,
+ RequestTimeout: "5s",
+ TracingKey: "jaeger",
+ MeshProviderPort: 8080,
+ KeepAliveInterval: "1m",
+ KeepAliveTimeout: "30s",
+ Params: map[string]string{
+ "key": "value",
+ },
+ Check: func() *bool { b := true; return &b }(),
+ RegistryIDs: []string{"reg1", "reg2"},
+ MethodsConfig: []*MethodConfig{
+ {Name: "method1"},
+ },
+ ProtocolClientConfig: DefaultClientProtocolConfig(),
+ }
+
+ opts := ref.GetOptions()
+ assert.NotNil(t, opts, "opts should not be nil")
+ assert.True(t, len(opts) > 0, "opts should have items")
+ })
+
+ t.Run("empty_reference_config", func(t *testing.T) {
+ emptyRef := &ReferenceConfig{}
+ emptyOpts := emptyRef.GetOptions()
+ // An empty config will return nil from GetOptions since all
fields are empty
+ if emptyOpts != nil {
+ assert.Equal(t, 0, len(emptyOpts), "empty ref config
should have no options")
+ }
+ })
+
+ t.Run("nil_reference_config_clone", func(t *testing.T) {
+ var nilRef *ReferenceConfig
+ cloned := nilRef.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("reference_config_with_retries_parsing", func(t *testing.T) {
+ ref := &ReferenceConfig{
+ Retries: "5",
+ }
+ opts := ref.GetOptions()
+ assert.NotNil(t, opts)
+ // Verify that a valid retries value produces an option
+ assert.Greater(t, len(opts), 0, "should have at least one
option from Retries")
+ // Verify retries option is present by checking that we have
options
+ hasRetriesOption := false
+ for _, opt := range opts {
+ // The option function should be WithReference_Retries
+ if opt != nil {
+ hasRetriesOption = true
+ break
+ }
+ }
+ assert.True(t, hasRetriesOption, "should contain a
retries-related option when Retries is a valid integer")
+ })
+
+ t.Run("reference_config_with_invalid_retries", func(t *testing.T) {
+ ref := &ReferenceConfig{
+ Retries: "invalid",
+ }
+ opts := ref.GetOptions()
+ // Invalid retries should not be added to options
+ // This is expected behavior - invalid values are silently
skipped
+ // Verify the returned options do not contain a retries option
+ // by confirming the invalid string is not converted
+
+ // GetOptions returns nil (or empty slice) when no options are
present
+ // Since Retries is the only field and it's invalid, no options
should be produced
+ if opts != nil {
+ // If opts is returned as a slice, it should be empty
since Retries is invalid
+ assert.Equal(t, 0, len(opts), "invalid retries value
should not produce any options")
+ }
+ // The fact that invalid retries is not in opts confirms it was
rejected
+ t.Logf("Invalid retries value was correctly skipped (opts=%v)",
opts)
+ })
+}
+
+// TestReferenceConfigOptions tests the option functions
+func TestReferenceConfigOptions(t *testing.T) {
+ t.Run("WithReference_InterfaceName", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_InterfaceName("com.test.Service")
+ opt(ref)
+ assert.Equal(t, "com.test.Service", ref.InterfaceName)
+ })
+
+ t.Run("WithReference_Check_true", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Check(true)
+ opt(ref)
+ assert.NotNil(t, ref.Check)
+ assert.True(t, *ref.Check)
+ })
+
+ t.Run("WithReference_Check_false", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Check(false)
+ opt(ref)
+ assert.NotNil(t, ref.Check)
+ assert.False(t, *ref.Check)
+ })
+
+ t.Run("WithReference_URL", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_URL("127.0.0.1:20880")
+ opt(ref)
+ assert.Equal(t, "127.0.0.1:20880", ref.URL)
+ })
+
+ t.Run("WithReference_Filter", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Filter("echo")
+ opt(ref)
+ assert.Equal(t, "echo", ref.Filter)
+ })
+
+ t.Run("WithReference_Protocol", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Protocol("tri")
+ opt(ref)
+ assert.Equal(t, "tri", ref.Protocol)
+ })
+
+ t.Run("WithReference_RegistryIDs", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_RegistryIDs([]string{"reg1", "reg2"})
+ opt(ref)
+ assert.Equal(t, 2, len(ref.RegistryIDs))
+ assert.Equal(t, "reg1", ref.RegistryIDs[0])
+ assert.Equal(t, "reg2", ref.RegistryIDs[1])
+ })
+
+ t.Run("WithReference_RegistryIDs_empty", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_RegistryIDs([]string{})
+ opt(ref)
+ assert.Equal(t, 0, len(ref.RegistryIDs))
+ })
+
+ t.Run("WithReference_Cluster", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Cluster("failover")
+ opt(ref)
+ assert.Equal(t, "failover", ref.Cluster)
+ })
+
+ t.Run("WithReference_LoadBalance", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_LoadBalance("random")
+ opt(ref)
+ assert.Equal(t, "random", ref.Loadbalance)
+ })
+
+ t.Run("WithReference_Retries", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Retries(3)
+ opt(ref)
+ assert.Equal(t, "3", ref.Retries)
+ })
+
+ t.Run("WithReference_Group", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Group("test")
+ opt(ref)
+ assert.Equal(t, "test", ref.Group)
+ })
+
+ t.Run("WithReference_Version", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Version("1.0.0")
+ opt(ref)
+ assert.Equal(t, "1.0.0", ref.Version)
+ })
+
+ t.Run("WithReference_Serialization", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Serialization("hessian2")
+ opt(ref)
+ assert.Equal(t, "hessian2", ref.Serialization)
+ })
+
+ t.Run("WithReference_ProviderBy", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_ProviderBy("provider")
+ opt(ref)
+ assert.Equal(t, "provider", ref.ProvidedBy)
+ })
+
+ t.Run("WithReference_Async_true", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Async(true)
+ opt(ref)
+ assert.True(t, ref.Async)
+ })
+
+ t.Run("WithReference_Async_false", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Async(false)
+ opt(ref)
+ assert.False(t, ref.Async)
+ })
+
+ t.Run("WithReference_Params", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ params := map[string]string{"key": "value", "key2": "value2"}
+ opt := WithReference_Params(params)
+ opt(ref)
+ assert.Equal(t, "value", ref.Params["key"])
+ assert.Equal(t, "value2", ref.Params["key2"])
+ })
+
+ t.Run("WithReference_Generic", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Generic("true")
+ opt(ref)
+ assert.Equal(t, "true", ref.Generic)
+ })
+
+ t.Run("WithReference_Sticky", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Sticky(true)
+ opt(ref)
+ assert.True(t, ref.Sticky)
+ })
+
+ t.Run("WithReference_RequestTimeout", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_RequestTimeout("5s")
+ opt(ref)
+ assert.Equal(t, "5s", ref.RequestTimeout)
+ })
+
+ t.Run("WithReference_Force", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_Force(true)
+ opt(ref)
+ assert.True(t, ref.ForceTag)
+ })
+
+ t.Run("WithReference_TracingKey", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_TracingKey("jaeger")
+ opt(ref)
+ assert.Equal(t, "jaeger", ref.TracingKey)
+ })
+
+ t.Run("WithReference_MeshProviderPort", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_MeshProviderPort(8080)
+ opt(ref)
+ assert.Equal(t, 8080, ref.MeshProviderPort)
+ })
+
+ t.Run("WithReference_KeepAliveInterval", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_KeepAliveInterval("1m")
+ opt(ref)
+ assert.Equal(t, "1m", ref.KeepAliveInterval)
+ })
+
+ t.Run("WithReference_KeepAliveTimeout", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ opt := WithReference_KeepAliveTimeout("30s")
+ opt(ref)
+ assert.Equal(t, "30s", ref.KeepAliveTimeout)
+ })
+
+ t.Run("WithReference_ProtocolClientConfig", func(t *testing.T) {
+ ref := &ReferenceConfig{}
+ pcc := DefaultClientProtocolConfig()
+ opt := WithReference_ProtocolClientConfig(pcc)
+ opt(ref)
+ assert.NotNil(t, ref.ProtocolClientConfig)
+ })
+}
+func TestRegistryConfigUseAsMetadataReport(t *testing.T) {
+ t.Run("empty_use_as_meta_report_defaults_to_true", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: ""}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.True(t, result)
+ })
+
+ t.Run("true_string", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "true"}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.True(t, result)
+ })
+
+ t.Run("false_string", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "false"}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.False(t, result)
+ })
+
+ t.Run("TRUE_uppercase", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "TRUE"}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.True(t, result)
+ })
+
+ t.Run("FALSE_uppercase", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "FALSE"}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.False(t, result)
+ })
+
+ t.Run("invalid_use_as_meta_report", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "invalid"}
+ result, err := reg.UseAsMetadataReport()
+ assert.NotNil(t, err)
+ assert.False(t, result)
+ })
+
+ t.Run("1_as_true", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "1"}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.True(t, result)
+ })
+
+ t.Run("0_as_false", func(t *testing.T) {
+ reg := &RegistryConfig{UseAsMetaReport: "0"}
+ result, err := reg.UseAsMetadataReport()
+ assert.Nil(t, err)
+ assert.False(t, result)
+ })
+}
+
+// TestRegistryConfigClone tests the Clone method of RegistryConfig
+func TestRegistryConfigClone(t *testing.T) {
+ t.Run("clone_full_registry_config", func(t *testing.T) {
+ reg := &RegistryConfig{
+ Protocol: "zookeeper",
+ Timeout: "5s",
+ Group: "test",
+ Namespace: "ns",
+ TTL: "15m",
+ Address: "localhost:2181",
+ Username: "user",
+ Password: "pass",
+ Simplified: true,
+ Preferred: true,
+ Zone: "zone1",
+ Weight: 100,
+ UseAsMetaReport: "true",
+ UseAsConfigCenter: "true",
+ RegistryType: "nacos",
+ Params: map[string]string{
+ "key1": "value1",
+ "key2": "value2",
+ },
+ }
+ cloned := reg.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, reg.Protocol, cloned.Protocol)
+ assert.Equal(t, reg.Timeout, cloned.Timeout)
+ assert.Equal(t, reg.Group, cloned.Group)
+ assert.Equal(t, reg.Namespace, cloned.Namespace)
+ assert.Equal(t, reg.TTL, cloned.TTL)
+ assert.Equal(t, reg.Address, cloned.Address)
+ assert.Equal(t, reg.Username, cloned.Username)
+ assert.Equal(t, reg.Password, cloned.Password)
+ assert.Equal(t, reg.Simplified, cloned.Simplified)
+ assert.Equal(t, reg.Preferred, cloned.Preferred)
+ assert.Equal(t, reg.Zone, cloned.Zone)
+ assert.Equal(t, reg.Weight, cloned.Weight)
+ assert.Equal(t, reg.UseAsMetaReport, cloned.UseAsMetaReport)
+ assert.Equal(t, reg.UseAsConfigCenter, cloned.UseAsConfigCenter)
+ assert.NotSame(t, reg, cloned)
+ assert.NotSame(t, reg.Params, cloned.Params)
+ assert.Equal(t, "value1", cloned.Params["key1"])
+ assert.Equal(t, "value2", cloned.Params["key2"])
+ })
+
+ t.Run("clone_nil_registry_config", func(t *testing.T) {
+ var reg *RegistryConfig
+ cloned := reg.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_empty_registry_config", func(t *testing.T) {
+ reg := &RegistryConfig{}
+ cloned := reg.Clone()
+ assert.NotNil(t, cloned)
+ assert.NotSame(t, reg, cloned)
+ })
+
+ t.Run("clone_with_empty_params", func(t *testing.T) {
+ reg := &RegistryConfig{
+ Protocol: "nacos",
+ Params: make(map[string]string),
+ }
+ cloned := reg.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, 0, len(cloned.Params))
+ assert.NotSame(t, reg.Params, cloned.Params)
+ })
+}
+
+// TestDefaultRegistryConfig tests DefaultRegistryConfig function
+func TestDefaultRegistryConfig(t *testing.T) {
+ t.Run("default_registry_config", func(t *testing.T) {
+ reg := DefaultRegistryConfig()
+ assert.NotNil(t, reg)
+ assert.Equal(t, "true", reg.UseAsMetaReport)
+ assert.Equal(t, "true", reg.UseAsConfigCenter)
+ assert.Equal(t, "5s", reg.Timeout)
+ assert.Equal(t, "15m", reg.TTL)
+ })
+}
+
+// TestDefaultRegistriesConfig tests DefaultRegistriesConfig function
+func TestDefaultRegistriesConfig(t *testing.T) {
+ t.Run("default_registries_config", func(t *testing.T) {
+ regs := DefaultRegistriesConfig()
+ assert.NotNil(t, regs)
+ assert.Equal(t, 0, len(regs))
+ })
+}
+
+// TestCloneRegistriesConfig tests CloneRegistriesConfig function
+func TestCloneRegistriesConfig(t *testing.T) {
+ t.Run("clone_multiple_registries", func(t *testing.T) {
+ regs := map[string]*RegistryConfig{
+ "reg1": {
+ Protocol: "zookeeper",
+ Address: "localhost:2181",
+ Params: map[string]string{
+ "key": "value",
+ },
+ },
+ "reg2": {
+ Protocol: "nacos",
+ Address: "localhost:8848",
+ Params: map[string]string{
+ "key2": "value2",
+ },
+ },
+ }
+ cloned := CloneRegistriesConfig(regs)
+ assert.Equal(t, 2, len(cloned))
+ assert.Equal(t, "zookeeper", cloned["reg1"].Protocol)
+ assert.Equal(t, "nacos", cloned["reg2"].Protocol)
+ assert.NotSame(t, regs["reg1"], cloned["reg1"])
+ assert.NotSame(t, regs["reg2"], cloned["reg2"])
+ assert.Equal(t, "value", cloned["reg1"].Params["key"])
+ assert.Equal(t, "value2", cloned["reg2"].Params["key2"])
+ })
+
+ t.Run("clone_nil_registries_config", func(t *testing.T) {
+ var regs map[string]*RegistryConfig
+ cloned := CloneRegistriesConfig(regs)
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_empty_registries_config", func(t *testing.T) {
+ regs := make(map[string]*RegistryConfig)
+ cloned := CloneRegistriesConfig(regs)
+ assert.NotNil(t, cloned)
+ assert.Equal(t, 0, len(cloned))
+ assert.NotSame(t, regs, cloned)
+ })
+
+ t.Run("clone_single_registry", func(t *testing.T) {
+ regs := map[string]*RegistryConfig{
+ "reg1": {
+ Protocol: "etcdv3",
+ Timeout: "10s",
+ Weight: 50,
+ Preferred: true,
+ },
+ }
+ cloned := CloneRegistriesConfig(regs)
+ assert.Equal(t, 1, len(cloned))
+ assert.Equal(t, "etcdv3", cloned["reg1"].Protocol)
+ assert.Equal(t, "10s", cloned["reg1"].Timeout)
+ assert.Equal(t, int64(50), cloned["reg1"].Weight)
+ assert.True(t, cloned["reg1"].Preferred)
+ })
+}
+func TestRouterConfigClone(t *testing.T) {
+ t.Run("clone_full_router_config", func(t *testing.T) {
+ router := &RouterConfig{
+ Scope: "service",
+ Key: "com.test.Service",
+ Priority: 10,
+ ScriptType: "javascript",
+ Script: "1==1",
+ Force: func() *bool {
+ b := true
+ return &b
+ }(),
+ Runtime: func() *bool {
+ b := false
+ return &b
+ }(),
+ Enabled: func() *bool {
+ b := true
+ return &b
+ }(),
+ Valid: func() *bool {
+ b := true
+ return &b
+ }(),
+ Conditions: []string{"condition1", "condition2"},
+ Tags: []Tag{
+ {
+ Name: "tag1",
+ Addresses: []string{"addr1", "addr2"},
+ },
+ {
+ Name: "tag2",
+ Addresses: []string{"addr3"},
+ },
+ },
+ }
+
+ cloned := router.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, router.Scope, cloned.Scope)
+ assert.Equal(t, router.Key, cloned.Key)
+ assert.Equal(t, router.Priority, cloned.Priority)
+ assert.Equal(t, router.ScriptType, cloned.ScriptType)
+ assert.Equal(t, router.Script, cloned.Script)
+ assert.NotSame(t, router, cloned)
+ assert.NotSame(t, router.Conditions, cloned.Conditions)
+ assert.NotSame(t, router.Tags, cloned.Tags)
+ assert.Equal(t, 2, len(cloned.Conditions))
+ assert.Equal(t, 2, len(cloned.Tags))
+ assert.Equal(t, "tag1", cloned.Tags[0].Name)
+ assert.Equal(t, "tag2", cloned.Tags[1].Name)
+ assert.Equal(t, 2, len(cloned.Tags[0].Addresses))
+ assert.Equal(t, 1, len(cloned.Tags[1].Addresses))
+ })
+
+ t.Run("clone_nil_router_config", func(t *testing.T) {
+ var router *RouterConfig
+ cloned := router.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_empty_router_config", func(t *testing.T) {
+ router := &RouterConfig{}
+ cloned := router.Clone()
+ assert.NotNil(t, cloned)
+ assert.NotSame(t, router, cloned)
+ })
+
+ t.Run("clone_router_config_with_nil_pointers", func(t *testing.T) {
+ router := &RouterConfig{
+ Scope: "service",
+ Key: "com.test.Service",
+ Force: nil,
+ Runtime: nil,
+ }
+ cloned := router.Clone()
+ assert.NotNil(t, cloned)
+ assert.Nil(t, cloned.Force)
+ assert.Nil(t, cloned.Runtime)
+ })
+
+ t.Run("clone_router_config_preserves_pointer_values", func(t
*testing.T) {
+ forceTrue := true
+ runtimeFalse := false
+ router := &RouterConfig{
+ Scope: "service",
+ Key: "test",
+ Force: &forceTrue,
+ Runtime: &runtimeFalse,
+ }
+ cloned := router.Clone()
+ assert.NotNil(t, cloned.Force)
+ assert.NotNil(t, cloned.Runtime)
+ assert.True(t, *cloned.Force)
+ assert.False(t, *cloned.Runtime)
+ assert.NotSame(t, router.Force, cloned.Force)
+ assert.NotSame(t, router.Runtime, cloned.Runtime)
+ })
+}
+
+// TestDefaultRouterConfig tests DefaultRouterConfig function
+func TestDefaultRouterConfig(t *testing.T) {
+ t.Run("default_router_config", func(t *testing.T) {
+ router := DefaultRouterConfig()
+ assert.NotNil(t, router)
+ assert.Equal(t, 0, len(router.Conditions))
+ assert.Equal(t, 0, len(router.Tags))
+ })
+}
+
+// TestTagStructure tests Tag structure and cloning
+func TestTagStructure(t *testing.T) {
+ t.Run("tag_with_addresses", func(t *testing.T) {
+ tag := Tag{
+ Name: "test",
+ Addresses: []string{"addr1", "addr2"},
+ }
+ assert.Equal(t, "test", tag.Name)
+ assert.Equal(t, 2, len(tag.Addresses))
+ })
+
+ t.Run("tag_with_empty_addresses", func(t *testing.T) {
+ tag := Tag{
+ Name: "test",
+ Addresses: []string{},
+ }
+ assert.Equal(t, 0, len(tag.Addresses))
+ })
+}
+
+// TestRouterConfigFields tests individual fields of RouterConfig
+func TestRouterConfigFields(t *testing.T) {
+ t.Run("router_config_scope", func(t *testing.T) {
+ router := &RouterConfig{
+ Scope: "application",
+ }
+ assert.Equal(t, "application", router.Scope)
+ })
+
+ t.Run("router_config_priority", func(t *testing.T) {
+ router := &RouterConfig{
+ Priority: 100,
+ }
+ assert.Equal(t, 100, router.Priority)
+ })
+
+ t.Run("router_config_script_type", func(t *testing.T) {
+ router := &RouterConfig{
+ ScriptType: "groovy",
+ Script: "1 == 1",
+ }
+ assert.Equal(t, "groovy", router.ScriptType)
+ assert.Equal(t, "1 == 1", router.Script)
+ })
+
+ t.Run("router_config_conditions_multiple", func(t *testing.T) {
+ router := &RouterConfig{
+ Conditions: []string{"cond1", "cond2", "cond3"},
+ }
+ assert.Equal(t, 3, len(router.Conditions))
+ assert.Equal(t, "cond1", router.Conditions[0])
+ assert.Equal(t, "cond3", router.Conditions[2])
+ })
+}
+func TestProtocolConfigClone(t *testing.T) {
+ t.Run("clone_full_protocol_config", func(t *testing.T) {
+ proto := &ProtocolConfig{
+ Name: "tri",
+ Ip: "127.0.0.1",
+ Port: "20880",
+ MaxServerSendMsgSize: "1mb",
+ MaxServerRecvMsgSize: "4mb",
+ TripleConfig: &TripleConfig{
+ MaxServerSendMsgSize: "2mb",
+ MaxServerRecvMsgSize: "4mb",
+ KeepAliveInterval: "1m",
+ KeepAliveTimeout: "30s",
+ Http3: DefaultHttp3Config(),
+ },
+ Params: map[string]string{
+ "key1": "value1",
+ "key2": "value2",
+ },
+ }
+
+ cloned := proto.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, proto.Name, cloned.Name)
+ assert.Equal(t, proto.Ip, cloned.Ip)
+ assert.Equal(t, proto.Port, cloned.Port)
+ assert.Equal(t, proto.MaxServerSendMsgSize,
cloned.MaxServerSendMsgSize)
+ assert.Equal(t, proto.MaxServerRecvMsgSize,
cloned.MaxServerRecvMsgSize)
+ assert.NotSame(t, proto, cloned)
+ assert.NotSame(t, proto.TripleConfig, cloned.TripleConfig)
+ assert.NotNil(t, cloned.TripleConfig)
+ })
+
+ t.Run("clone_nil_protocol_config", func(t *testing.T) {
+ var proto *ProtocolConfig
+ cloned := proto.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_protocol_config_with_nil_triple_config", func(t
*testing.T) {
+ proto := &ProtocolConfig{
+ Name: "dubbo",
+ Port: "20880",
+ }
+ cloned := proto.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, "dubbo", cloned.Name)
+ })
+
+ t.Run("clone_protocol_config_preserves_all_fields", func(t *testing.T) {
+ proto := &ProtocolConfig{
+ Name: "http",
+ Ip: "192.168.1.1",
+ Port: "8080",
+ MaxServerSendMsgSize: "10mb",
+ MaxServerRecvMsgSize: "10mb",
+ }
+ cloned := proto.Clone()
+ assert.Equal(t, "http", cloned.Name)
+ assert.Equal(t, "192.168.1.1", cloned.Ip)
+ assert.Equal(t, "8080", cloned.Port)
+ assert.Equal(t, "10mb", cloned.MaxServerSendMsgSize)
+ assert.Equal(t, "10mb", cloned.MaxServerRecvMsgSize)
+ })
+}
+
+// TestDefaultProtocolConfig tests DefaultProtocolConfig function
+func TestDefaultProtocolConfig(t *testing.T) {
+ t.Run("default_protocol_config", func(t *testing.T) {
+ proto := DefaultProtocolConfig()
+ assert.NotNil(t, proto)
+ assert.NotEmpty(t, proto.Name)
+ assert.NotEmpty(t, proto.Port)
+ assert.NotNil(t, proto.TripleConfig)
+ })
+}
+
+// TestProtocolConfigFields tests individual fields of ProtocolConfig
+func TestProtocolConfigFields(t *testing.T) {
+ t.Run("protocol_config_name", func(t *testing.T) {
+ proto := &ProtocolConfig{Name: "dubbo"}
+ assert.Equal(t, "dubbo", proto.Name)
+ })
+
+ t.Run("protocol_config_ip", func(t *testing.T) {
+ proto := &ProtocolConfig{Ip: "10.0.0.1"}
+ assert.Equal(t, "10.0.0.1", proto.Ip)
+ })
+
+ t.Run("protocol_config_port", func(t *testing.T) {
+ proto := &ProtocolConfig{Port: "9090"}
+ assert.Equal(t, "9090", proto.Port)
+ })
+
+ t.Run("protocol_config_with_params", func(t *testing.T) {
+ params := map[string]string{
+ "param1": "value1",
+ "param2": "value2",
+ }
+ proto := &ProtocolConfig{
+ Name: "tri",
+ Params: params,
+ }
+ assert.NotNil(t, proto.Params)
+ })
+
+ t.Run("protocol_config_with_triple_config", func(t *testing.T) {
+ tripleConfig := &TripleConfig{
+ KeepAliveInterval: "2m",
+ KeepAliveTimeout: "60s",
+ }
+ proto := &ProtocolConfig{
+ Name: "tri",
+ TripleConfig: tripleConfig,
+ }
+ assert.NotNil(t, proto.TripleConfig)
+ assert.Equal(t, "2m", proto.TripleConfig.KeepAliveInterval)
+ assert.Equal(t, "60s", proto.TripleConfig.KeepAliveTimeout)
+ })
+}
+
+// TestTripleConfigClone tests the Clone method of TripleConfig
+func TestTripleConfigClone(t *testing.T) {
+ t.Run("clone_full_triple_config", func(t *testing.T) {
+ triple := &TripleConfig{
+ MaxServerSendMsgSize: "5mb",
+ MaxServerRecvMsgSize: "5mb",
+ KeepAliveInterval: "3m",
+ KeepAliveTimeout: "45s",
+ Http3: DefaultHttp3Config(),
+ }
+ cloned := triple.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, triple.MaxServerSendMsgSize,
cloned.MaxServerSendMsgSize)
+ assert.Equal(t, triple.MaxServerRecvMsgSize,
cloned.MaxServerRecvMsgSize)
+ assert.Equal(t, triple.KeepAliveInterval,
cloned.KeepAliveInterval)
+ assert.Equal(t, triple.KeepAliveTimeout,
cloned.KeepAliveTimeout)
+ assert.NotSame(t, triple, cloned)
+ assert.NotSame(t, triple.Http3, cloned.Http3)
+ })
+
+ t.Run("clone_nil_triple_config", func(t *testing.T) {
+ var triple *TripleConfig
+ cloned := triple.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_triple_config_with_nil_http3", func(t *testing.T) {
+ triple := &TripleConfig{
+ MaxServerSendMsgSize: "1mb",
+ }
+ cloned := triple.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, "1mb", cloned.MaxServerSendMsgSize)
+ })
+}
+
+// TestDefaultTripleConfig tests DefaultTripleConfig function
+func TestDefaultTripleConfig(t *testing.T) {
+ t.Run("default_triple_config", func(t *testing.T) {
+ triple := DefaultTripleConfig()
+ assert.NotNil(t, triple)
+ assert.NotNil(t, triple.Http3)
+ })
+}
+
+// TestHttp3ConfigClone tests the Clone method of Http3Config
+func TestHttp3ConfigClone(t *testing.T) {
+ t.Run("clone_http3_config", func(t *testing.T) {
+ http3 := &Http3Config{
+ Enable: true,
+ Negotiation: false,
+ }
+ cloned := http3.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, http3.Enable, cloned.Enable)
+ assert.Equal(t, http3.Negotiation, cloned.Negotiation)
+ })
+
+ t.Run("clone_nil_http3_config", func(t *testing.T) {
+ var http3 *Http3Config
+ cloned := http3.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_http3_config_with_defaults", func(t *testing.T) {
+ http3 := DefaultHttp3Config()
+ cloned := http3.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, http3.Enable, cloned.Enable)
+ assert.Equal(t, http3.Negotiation, cloned.Negotiation)
+ })
+}
+
+// TestDefaultHttp3Config tests DefaultHttp3Config function
+func TestDefaultHttp3Config(t *testing.T) {
+ t.Run("default_http3_config", func(t *testing.T) {
+ http3 := DefaultHttp3Config()
+ assert.NotNil(t, http3)
+ })
+}
+func TestConsumerConfigClone(t *testing.T) {
+ t.Run("clone_full_consumer_config", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ Filter: "echo",
+ Protocol: "dubbo",
+ RequestTimeout: "5s",
+ ProxyFactory: "default",
+ Check: true,
+ AdaptiveService: true,
+ TracingKey: "jaeger",
+ MeshEnabled: true,
+ MaxWaitTimeForServiceDiscovery: "5s",
+ RegistryIDs: []string{"reg1",
"reg2"},
+ References: map[string]*ReferenceConfig{
+ "ref1": {
+ InterfaceName: "com.test.Service1",
+ },
+ "ref2": {
+ InterfaceName: "com.test.Service2",
+ },
+ },
+ }
+
+ cloned := consumer.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, consumer.Filter, cloned.Filter)
+ assert.Equal(t, consumer.Protocol, cloned.Protocol)
+ assert.Equal(t, consumer.RequestTimeout, cloned.RequestTimeout)
+ assert.Equal(t, consumer.Check, cloned.Check)
+ assert.Equal(t, consumer.AdaptiveService,
cloned.AdaptiveService)
+ assert.NotSame(t, consumer, cloned)
+ assert.NotSame(t, consumer.References, cloned.References)
+ assert.Equal(t, 2, len(cloned.References))
+ assert.Equal(t, "com.test.Service1",
cloned.References["ref1"].InterfaceName)
+ })
+
+ t.Run("clone_nil_consumer_config", func(t *testing.T) {
+ var consumer *ConsumerConfig
+ cloned := consumer.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_consumer_config_with_empty_references", func(t *testing.T)
{
+ consumer := &ConsumerConfig{
+ Filter: "echo",
+ }
+ cloned := consumer.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, "echo", cloned.Filter)
+ assert.NotSame(t, consumer, cloned)
+ })
+}
+
+// TestDefaultConsumerConfig tests DefaultConsumerConfig function
+func TestDefaultConsumerConfig(t *testing.T) {
+ t.Run("default_consumer_config", func(t *testing.T) {
+ consumer := DefaultConsumerConfig()
+ assert.NotNil(t, consumer)
+ assert.True(t, consumer.Check)
+ assert.NotNil(t, consumer.References)
+ assert.Equal(t, 0, len(consumer.References))
+ })
+}
+
+// TestConsumerConfigFields tests individual fields of ConsumerConfig
+func TestConsumerConfigFields(t *testing.T) {
+ t.Run("consumer_config_filter", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ Filter: "echo",
+ }
+ assert.Equal(t, "echo", consumer.Filter)
+ })
+
+ t.Run("consumer_config_protocol", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ Protocol: "tri",
+ }
+ assert.Equal(t, "tri", consumer.Protocol)
+ })
+
+ t.Run("consumer_config_timeout", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ RequestTimeout: "10s",
+ }
+ assert.Equal(t, "10s", consumer.RequestTimeout)
+ })
+
+ t.Run("consumer_config_check", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ Check: false,
+ }
+ assert.False(t, consumer.Check)
+ })
+
+ t.Run("consumer_config_adaptive_service", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ AdaptiveService: true,
+ }
+ assert.True(t, consumer.AdaptiveService)
+ })
+
+ t.Run("consumer_config_registry_ids", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ RegistryIDs: []string{"reg1", "reg2", "reg3"},
+ }
+ assert.Equal(t, 3, len(consumer.RegistryIDs))
+ })
+
+ t.Run("consumer_config_mesh_enabled", func(t *testing.T) {
+ consumer := &ConsumerConfig{
+ MeshEnabled: true,
+ }
+ assert.True(t, consumer.MeshEnabled)
+ })
+}
+func TestServiceConfigClone(t *testing.T) {
+ t.Run("clone_full_service_config", func(t *testing.T) {
+ service := &ServiceConfig{
+ Filter: "echo",
+ Interface: "com.test.Service",
+ Group: "test",
+ Version: "1.0.0",
+ Cluster: "failover",
+ Loadbalance: "random",
+ NotRegister: true,
+ Weight: 100,
+ TracingKey: "jaeger",
+ Auth: "token",
+ Token: "abc123",
+ AccessLog: "true",
+ TpsLimiter: "default",
+ TpsLimitInterval: "1000",
+ TpsLimitRate: "100",
+ TpsLimitStrategy: "default",
+ ExecuteLimit: "10",
+ ExecuteLimitRejectedHandler: "default",
+ ParamSign: "true",
+ Tag: "prod",
+ Warmup: "60",
+ Retries: "3",
+ Serialization: "hessian2",
+ ProtocolIDs: []string{"proto1"},
+ RegistryIDs: []string{"reg1"},
+ Methods: []*MethodConfig{
+ {Name: "method1"},
+ },
+ Params: map[string]string{
+ "key": "value",
+ },
+ RCProtocolsMap: map[string]*ProtocolConfig{
+ "proto1": {Name: "tri"},
+ },
+ RCRegistriesMap: map[string]*RegistryConfig{
+ "reg1": {Protocol: "zookeeper"},
+ },
+ }
+
+ cloned := service.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, service.Filter, cloned.Filter)
+ assert.Equal(t, service.Interface, cloned.Interface)
+ assert.Equal(t, service.Group, cloned.Group)
+ assert.Equal(t, service.Version, cloned.Version)
+ assert.NotSame(t, service, cloned)
+ assert.NotSame(t, service.Params, cloned.Params)
+ assert.Equal(t, "value", cloned.Params["key"])
+ assert.Equal(t, 1, len(cloned.ProtocolIDs))
+ assert.Equal(t, 1, len(cloned.RegistryIDs))
+ })
+
+ t.Run("clone_nil_service_config", func(t *testing.T) {
+ var service *ServiceConfig
+ cloned := service.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_empty_service_config", func(t *testing.T) {
+ service := &ServiceConfig{}
+ cloned := service.Clone()
+ assert.NotNil(t, cloned)
+ assert.NotSame(t, service, cloned)
+ })
+
+ t.Run("clone_service_config_with_maps", func(t *testing.T) {
+ service := &ServiceConfig{
+ Interface: "com.test.Service",
+ RCProtocolsMap: map[string]*ProtocolConfig{
+ "proto1": {Name: "tri", Port: "20880"},
+ "proto2": {Name: "dubbo", Port: "20881"},
+ },
+ RCRegistriesMap: map[string]*RegistryConfig{
+ "reg1": {Protocol: "zookeeper", Address:
"localhost:2181"},
+ "reg2": {Protocol: "nacos", Address:
"localhost:8848"},
+ },
+ }
+ cloned := service.Clone()
+ assert.Equal(t, 2, len(cloned.RCProtocolsMap))
+ assert.Equal(t, 2, len(cloned.RCRegistriesMap))
+ assert.NotSame(t, service.RCProtocolsMap, cloned.RCProtocolsMap)
+ assert.NotSame(t, service.RCRegistriesMap,
cloned.RCRegistriesMap)
+ })
+}
+
+// TestDefaultServiceConfig tests DefaultServiceConfig function
+func TestDefaultServiceConfig(t *testing.T) {
+ t.Run("default_service_config", func(t *testing.T) {
+ service := DefaultServiceConfig()
+ assert.NotNil(t, service)
+ assert.NotNil(t, service.Methods)
+ assert.NotNil(t, service.Params)
+ assert.NotNil(t, service.RCProtocolsMap)
+ assert.NotNil(t, service.RCRegistriesMap)
+ assert.Equal(t, 0, len(service.Methods))
+ assert.Equal(t, 0, len(service.Params))
+ })
+}
+
+// TestServiceConfigFields tests individual fields of ServiceConfig
+func TestServiceConfigFields(t *testing.T) {
+ t.Run("service_config_interface", func(t *testing.T) {
+ service := &ServiceConfig{
+ Interface: "com.test.Service",
+ }
+ assert.Equal(t, "com.test.Service", service.Interface)
+ })
+
+ t.Run("service_config_version", func(t *testing.T) {
+ service := &ServiceConfig{
+ Version: "2.0.0",
+ }
+ assert.Equal(t, "2.0.0", service.Version)
+ })
+
+ t.Run("service_config_group", func(t *testing.T) {
+ service := &ServiceConfig{
+ Group: "production",
+ }
+ assert.Equal(t, "production", service.Group)
+ })
+
+ t.Run("service_config_cluster", func(t *testing.T) {
+ service := &ServiceConfig{
+ Cluster: "forking",
+ }
+ assert.Equal(t, "forking", service.Cluster)
+ })
+
+ t.Run("service_config_loadbalance", func(t *testing.T) {
+ service := &ServiceConfig{
+ Loadbalance: "leastactive",
+ }
+ assert.Equal(t, "leastactive", service.Loadbalance)
+ })
+
+ t.Run("service_config_weight", func(t *testing.T) {
+ service := &ServiceConfig{
+ Weight: 200,
+ }
+ assert.Equal(t, int64(200), service.Weight)
+ })
+
+ t.Run("service_config_not_register", func(t *testing.T) {
+ service := &ServiceConfig{
+ NotRegister: true,
+ }
+ assert.True(t, service.NotRegister)
+ })
+
+ t.Run("service_config_protocol_ids", func(t *testing.T) {
+ service := &ServiceConfig{
+ ProtocolIDs: []string{"proto1", "proto2"},
+ }
+ assert.Equal(t, 2, len(service.ProtocolIDs))
+ })
+
+ t.Run("service_config_registry_ids", func(t *testing.T) {
+ service := &ServiceConfig{
+ RegistryIDs: []string{"reg1"},
+ }
+ assert.Equal(t, 1, len(service.RegistryIDs))
+ })
+}
+
+// TestServiceOptionFunc tests the ServiceOption function type
+func TestServiceOptionFunc(t *testing.T) {
+ t.Run("apply_service_option", func(t *testing.T) {
+ service := &ServiceConfig{}
+ opt := func(cfg *ServiceConfig) {
+ cfg.Interface = "com.test.Service"
+ cfg.Version = "1.0.0"
+ }
+ opt(service)
+ assert.Equal(t, "com.test.Service", service.Interface)
+ assert.Equal(t, "1.0.0", service.Version)
+ })
+}
+func TestProviderConfigClone(t *testing.T) {
+ t.Run("clone_full_provider_config", func(t *testing.T) {
+ provider := &ProviderConfig{
+ Filter: "echo",
+ Register: true,
+ RegistryIDs: []string{"reg1", "reg2"},
+ ProtocolIDs: []string{"proto1"},
+ TracingKey: "jaeger",
+ ProxyFactory: "default",
+ AdaptiveService: true,
+ AdaptiveServiceVerbose: true,
+ ConfigType: map[string]string{"key":
"value"},
+ Services: map[string]*ServiceConfig{
+ "service1": {Interface: "com.test.Service1"},
+ },
+ ServiceConfig: ServiceConfig{
+ Interface: "com.test.BaseService",
+ Group: "test",
+ Version: "1.0.0",
+ },
+ }
+
+ cloned := provider.Clone()
+ assert.NotNil(t, cloned)
+ assert.Equal(t, provider.Filter, cloned.Filter)
+ assert.Equal(t, provider.Register, cloned.Register)
+ assert.NotSame(t, provider, cloned)
+ assert.NotSame(t, provider.Services, cloned.Services)
+
+ // Verify RegistryIDs is a true deep copy by mutating the clone
+ assert.Equal(t, len(provider.RegistryIDs),
len(cloned.RegistryIDs))
+ assert.Equal(t, provider.RegistryIDs, cloned.RegistryIDs)
+ if len(cloned.RegistryIDs) > 0 {
+ originalValue := cloned.RegistryIDs[0]
+ cloned.RegistryIDs[0] = "modified"
+ assert.NotEqual(t, provider.RegistryIDs[0],
cloned.RegistryIDs[0])
+ cloned.RegistryIDs[0] = originalValue
+ }
+ cloned.RegistryIDs = append(cloned.RegistryIDs, "new_registry")
+ assert.NotEqual(t, len(provider.RegistryIDs),
len(cloned.RegistryIDs))
+
+ // Verify ProtocolIDs is a true deep copy by mutating the clone
+ assert.Equal(t, len(provider.ProtocolIDs),
len(cloned.ProtocolIDs))
+ assert.Equal(t, provider.ProtocolIDs, cloned.ProtocolIDs)
+ if len(cloned.ProtocolIDs) > 0 {
+ originalValue := cloned.ProtocolIDs[0]
+ cloned.ProtocolIDs[0] = "modified"
+ assert.NotEqual(t, provider.ProtocolIDs[0],
cloned.ProtocolIDs[0])
+ cloned.ProtocolIDs[0] = originalValue
+ }
+ cloned.ProtocolIDs = append(cloned.ProtocolIDs, "new_protocol")
+ assert.NotEqual(t, len(provider.ProtocolIDs),
len(cloned.ProtocolIDs))
+
+ // Verify Services is a true deep copy by mutating the clone
+ assert.Equal(t, len(provider.Services), len(cloned.Services))
+ cloned.Services["service2"] = &ServiceConfig{Interface:
"com.test.Service2"}
+ assert.NotEqual(t, len(provider.Services), len(cloned.Services))
+ assert.NotContains(t, provider.Services, "service2")
+ assert.Contains(t, cloned.Services, "service2")
+ })
+
+ t.Run("clone_nil_provider_config", func(t *testing.T) {
+ var provider *ProviderConfig
+ cloned := provider.Clone()
+ assert.Nil(t, cloned)
+ })
+
+ t.Run("clone_default_provider_config", func(t *testing.T) {
+ provider := DefaultProviderConfig()
+ cloned := provider.Clone()
+ assert.NotNil(t, cloned)
+ assert.NotSame(t, provider, cloned)
+
+ // Verify RegistryIDs is a true deep copy
+ if len(provider.RegistryIDs) > 0 {
+ assert.Equal(t, provider.RegistryIDs,
cloned.RegistryIDs)
+ cloned.RegistryIDs[0] = "modified"
+ assert.NotEqual(t, provider.RegistryIDs[0],
cloned.RegistryIDs[0])
+ }
+
+ // Verify ProtocolIDs is a true deep copy
+ if len(provider.ProtocolIDs) > 0 {
+ assert.Equal(t, provider.ProtocolIDs,
cloned.ProtocolIDs)
+ cloned.ProtocolIDs[0] = "modified"
+ assert.NotEqual(t, provider.ProtocolIDs[0],
cloned.ProtocolIDs[0])
Review Comment:
After modifying cloned.RegistryIDs[0] on line 1561, the test asserts that
provider.RegistryIDs[0] should be different. However, if the test passes, it
means the original was not affected by the mutation, which is the desired
behavior. But there's no cleanup here - the cloned data remains mutated. While
this doesn't break the test, it creates inconsistency with the pattern used
above where values were restored. Consider either consistently restoring values
or consistently not restoring them across all clone tests.
```suggestion
assert.Equal(t, provider.RegistryIDs,
cloned.RegistryIDs)
originalRegistryID := cloned.RegistryIDs[0]
cloned.RegistryIDs[0] = "modified"
assert.NotEqual(t, provider.RegistryIDs[0],
cloned.RegistryIDs[0])
// restore mutated value to keep cloned config
consistent for any subsequent checks
cloned.RegistryIDs[0] = originalRegistryID
}
// Verify ProtocolIDs is a true deep copy
if len(provider.ProtocolIDs) > 0 {
assert.Equal(t, provider.ProtocolIDs,
cloned.ProtocolIDs)
originalProtocolID := cloned.ProtocolIDs[0]
cloned.ProtocolIDs[0] = "modified"
assert.NotEqual(t, provider.ProtocolIDs[0],
cloned.ProtocolIDs[0])
// restore mutated value to keep cloned config
consistent for any subsequent checks
cloned.ProtocolIDs[0] = originalProtocolID
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]