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

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


The following commit(s) were added to refs/heads/develop by this push:
     new a65cdc1ff chore: add doc comments and unit tests for metadata 
customizers (#3678)
a65cdc1ff is described below

commit a65cdc1ff7dabcb4a6dbf23afa3e151833932bfc
Author: DaWesen <[email protected]>
AuthorDate: Wed Aug 19 12:47:48 2026 +0800

    chore: add doc comments and unit tests for metadata customizers (#3678)
    
    * chore: add doc comments and unit tests for metadata customizers
    
    * chore: align import blocks with imports-formatter
    
    * chore: resolve testifylint issues in metadata customizer tests
    
    * chore: align customizer comments with metadata service URL semantics
---
 .../metadata_service_url_params_customizer.go      |   9 ++
 .../metadata_service_url_params_customizer_test.go |  61 +++++++-
 .../metadata_service_version_customizer.go         |  10 +-
 .../metadata_service_version_customizer_test.go    |  99 +++++++++++++
 .../protocol_ports_metadata_customizer.go          |   8 +-
 .../protocol_ports_metadata_customizer_test.go     | 156 +++++++++++++++++++++
 6 files changed, 334 insertions(+), 9 deletions(-)

diff --git 
a/registry/servicediscovery/customizer/metadata_service_url_params_customizer.go
 
b/registry/servicediscovery/customizer/metadata_service_url_params_customizer.go
index 45e558d06..64ff31c07 100644
--- 
a/registry/servicediscovery/customizer/metadata_service_url_params_customizer.go
+++ 
b/registry/servicediscovery/customizer/metadata_service_url_params_customizer.go
@@ -46,6 +46,9 @@ func init() {
        
extension.AddCustomizers(&metadataServiceURLParamsMetadataCustomizer{exceptKeys:
 exceptKeys})
 }
 
+// metadataServiceURLParamsMetadataCustomizer writes the metadata service URL
+// params into the instance metadata as JSON.
+// exceptKeys is currently unused.
 type metadataServiceURLParamsMetadataCustomizer struct {
        exceptKeys *gxset.HashSet
 }
@@ -55,6 +58,9 @@ func (m *metadataServiceURLParamsMetadataCustomizer) 
GetPriority() int {
        return 0
 }
 
+// Customize writes the metadata service URL params into the instance metadata
+// under MetadataServiceURLParamsPropertyName; when the metadata service URL is
+// nil, it returns without writing, otherwise the params JSON overwrites the 
key.
 func (m *metadataServiceURLParamsMetadataCustomizer) Customize(instance 
registry.ServiceInstance) {
        // TODO: GetMetadataService() is a global singleton and returns the 
same metadata service URL
        // regardless of which registry this instance belongs to. In a 
multi-registry setup each
@@ -74,6 +80,9 @@ func (m *metadataServiceURLParamsMetadataCustomizer) 
Customize(instance registry
        instance.GetMetadata()[constant.MetadataServiceURLParamsPropertyName] = 
string(str)
 }
 
+// convertToParams converts the URL params into a map[string]string.
+// Only keys contained in info.IncludeKeys with non-empty values are kept;
+// the port and protocol are always appended from the URL.
 func (m *metadataServiceURLParamsMetadataCustomizer) convertToParams(url 
*common.URL) map[string]string {
        // those keys are useless
        p := make(map[string]string, len(url.GetParams()))
diff --git 
a/registry/servicediscovery/customizer/metadata_service_url_params_customizer_test.go
 
b/registry/servicediscovery/customizer/metadata_service_url_params_customizer_test.go
index 7ed37cadd..95b7b9579 100644
--- 
a/registry/servicediscovery/customizer/metadata_service_url_params_customizer_test.go
+++ 
b/registry/servicediscovery/customizer/metadata_service_url_params_customizer_test.go
@@ -28,18 +28,67 @@ import (
 )
 
 import (
+       "dubbo.apache.org/dubbo-go/v3/common"
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
        "dubbo.apache.org/dubbo-go/v3/registry"
 )
 
-func TestMetadataServiceURLParamsMetadataCustomizer(t *testing.T) {
-
+func TestMetadataServiceURLParamsMetadataCustomizerGetPriority(t *testing.T) {
        msup := &metadataServiceURLParamsMetadataCustomizer{exceptKeys: 
gxset.NewSet()}
        assert.Equal(t, 0, msup.GetPriority())
-
-       msup.Customize(createInstance())
 }
 
-func createInstance() registry.ServiceInstance {
+// TestMetadataServiceURLParamsCustomizeNilURL verifies that when the metadata
+// service URL is not exported (nil), Customize writes nothing into metadata.
+// The URL comes from the global metadata.GetMetadataService() singleton whose
+// metadataUrl is nil by default; there is no exported setter and no test in
+// this package modifies it, so the nil state is deterministic.
+func TestMetadataServiceURLParamsCustomizeNilURL(t *testing.T) {
+       msup := &metadataServiceURLParamsMetadataCustomizer{exceptKeys: 
gxset.NewSet()}
        ins := &registry.DefaultServiceInstance{}
-       return ins
+       msup.Customize(ins)
+       _, ok := 
ins.GetMetadata()[constant.MetadataServiceURLParamsPropertyName]
+       assert.False(t, ok, "nothing should be written when the metadata 
service URL is nil")
+}
+
+func TestConvertToParams(t *testing.T) {
+       msup := &metadataServiceURLParamsMetadataCustomizer{exceptKeys: 
gxset.NewSet()}
+
+       u := common.NewURLWithOptions(
+               common.WithProtocol("dubbo"),
+               common.WithPort("20880"),
+               common.WithParamsValue(constant.TimeoutKey, "3000"), // in 
IncludeKeys, should be kept
+               common.WithParamsValue(constant.PathKey, "/path"),   // in 
IncludeKeys, should be kept
+               common.WithParamsValue(constant.VersionKey, ""),     // empty 
value, should be dropped
+               common.WithParamsValue("custom.arbitrary.key", "x"), // not in 
IncludeKeys, should be dropped
+       )
+
+       ps := msup.convertToParams(u)
+
+       assert.Equal(t, "3000", ps[constant.TimeoutKey])
+       assert.Equal(t, "/path", ps[constant.PathKey])
+       // port/protocol are always appended even if absent from URL params
+       assert.Equal(t, "dubbo", ps[constant.ProtocolKey])
+       assert.Equal(t, "20880", ps[constant.PortKey])
+       // empty values are dropped
+       _, ok := ps[constant.VersionKey]
+       assert.False(t, ok, "empty value param should be dropped")
+       // keys outside info.IncludeKeys are dropped
+       _, ok = ps["custom.arbitrary.key"]
+       assert.False(t, ok, "param not in IncludeKeys should be dropped")
+}
+
+func TestConvertToParamsAlwaysAppendsPortAndProtocol(t *testing.T) {
+       msup := &metadataServiceURLParamsMetadataCustomizer{exceptKeys: 
gxset.NewSet()}
+
+       // URL without explicit port/protocol params
+       u := common.NewURLWithOptions(
+               common.WithProtocol("tri"),
+               common.WithPort("50051"),
+       )
+
+       ps := msup.convertToParams(u)
+
+       assert.Equal(t, "tri", ps[constant.ProtocolKey])
+       assert.Equal(t, "50051", ps[constant.PortKey])
 }
diff --git 
a/registry/servicediscovery/customizer/metadata_service_version_customizer.go 
b/registry/servicediscovery/customizer/metadata_service_version_customizer.go
index efc4f2f99..0fc5285cd 100644
--- 
a/registry/servicediscovery/customizer/metadata_service_version_customizer.go
+++ 
b/registry/servicediscovery/customizer/metadata_service_version_customizer.go
@@ -35,7 +35,8 @@ func init() {
        extension.AddCustomizers(&MetadtaServiceVersionCustomizer{})
 }
 
-// MetadtaServiceVersionCustomizer will try to add meta-v key to instance 
metadata
+// MetadtaServiceVersionCustomizer writes the metadata service version into the
+// instance metadata according to the protocol of the metadata service URL.
 type MetadtaServiceVersionCustomizer struct {
 }
 
@@ -44,7 +45,12 @@ func (p *MetadtaServiceVersionCustomizer) GetPriority() int {
        return 0
 }
 
-// Customize put the the string like [{"protocol": "dubbo", "port": 123}] into 
instance's metadata
+// Customize writes the metadata service version into the instance metadata
+// under MetadataVersion ("meta-v"). It only runs when the metadata storage
+// type is local. The protocol is read from the params JSON stored at
+// MetadataServiceURLParamsPropertyName: tri writes v2, any other protocol
+// (including empty) writes v1. An unparsable params JSON leaves the metadata
+// unchanged, otherwise the version overwrites the previous value.
 func (p *MetadtaServiceVersionCustomizer) Customize(instance 
registry.ServiceInstance) {
        if instance.GetMetadata()[constant.MetadataStorageTypePropertyName] != 
constant.DefaultMetadataStorageType {
                return
diff --git 
a/registry/servicediscovery/customizer/metadata_service_version_customizer_test.go
 
b/registry/servicediscovery/customizer/metadata_service_version_customizer_test.go
new file mode 100644
index 000000000..86377cbe3
--- /dev/null
+++ 
b/registry/servicediscovery/customizer/metadata_service_version_customizer_test.go
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package customizer
+
+import (
+       "testing"
+)
+
+import (
+       "github.com/stretchr/testify/assert"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+       "dubbo.apache.org/dubbo-go/v3/registry"
+)
+
+func TestMetadtaServiceVersionCustomizerGetPriority(t *testing.T) {
+       p := &MetadtaServiceVersionCustomizer{}
+       assert.Equal(t, 0, p.GetPriority())
+}
+
+// TestMetadtaServiceVersionCustomizerTriProtocol verifies that a tri metadata
+// service URL writes v2.
+func TestMetadtaServiceVersionCustomizerTriProtocol(t *testing.T) {
+       p := &MetadtaServiceVersionCustomizer{}
+       ins := newVersionInstance(`{"protocol":"tri","port":"20880"}`)
+       p.Customize(ins)
+       assert.Equal(t, constant.MetadataServiceV2Version, 
ins.GetMetadata()[constant.MetadataVersion])
+}
+
+// TestMetadtaServiceVersionCustomizerDubboProtocol verifies that a dubbo
+// metadata service URL writes v1.
+func TestMetadtaServiceVersionCustomizerDubboProtocol(t *testing.T) {
+       p := &MetadtaServiceVersionCustomizer{}
+       ins := newVersionInstance(`{"protocol":"dubbo","port":"20880"}`)
+       p.Customize(ins)
+       assert.Equal(t, constant.MetadataServiceV1Version, 
ins.GetMetadata()[constant.MetadataVersion])
+}
+
+// TestMetadtaServiceVersionCustomizerUnknownProtocol verifies that any 
protocol
+// other than tri (including an absent one) falls back to v1.
+func TestMetadtaServiceVersionCustomizerUnknownProtocol(t *testing.T) {
+       p := &MetadtaServiceVersionCustomizer{}
+       ins := newVersionInstance(`{"port":"20880"}`)
+       p.Customize(ins)
+       assert.Equal(t, constant.MetadataServiceV1Version, 
ins.GetMetadata()[constant.MetadataVersion])
+}
+
+// TestMetadtaServiceVersionCustomizerNonLocalStorage verifies that the version
+// is not written when the metadata storage type is not local.
+func TestMetadtaServiceVersionCustomizerNonLocalStorage(t *testing.T) {
+       p := &MetadtaServiceVersionCustomizer{}
+       ins := &registry.DefaultServiceInstance{
+               Metadata: map[string]string{
+                       constant.MetadataStorageTypePropertyName:      "remote",
+                       constant.MetadataServiceURLParamsPropertyName: 
`{"protocol":"tri","port":"20880"}`,
+               },
+       }
+       p.Customize(ins)
+       _, ok := ins.GetMetadata()[constant.MetadataVersion]
+       assert.False(t, ok, "version should not be written for non-local 
storage type")
+}
+
+// TestMetadtaServiceVersionCustomizerInvalidJSON verifies that an unparsable
+// params JSON leaves the metadata unchanged.
+func TestMetadtaServiceVersionCustomizerInvalidJSON(t *testing.T) {
+       p := &MetadtaServiceVersionCustomizer{}
+       ins := newVersionInstance("not-a-json")
+       p.Customize(ins)
+       _, ok := ins.GetMetadata()[constant.MetadataVersion]
+       assert.False(t, ok, "version should not be written when the params JSON 
is invalid")
+}
+
+// newVersionInstance creates an instance with local storage type and the given
+// metadata service url params JSON.
+func newVersionInstance(paramsJSON string) registry.ServiceInstance {
+       return &registry.DefaultServiceInstance{
+               Metadata: map[string]string{
+                       constant.MetadataStorageTypePropertyName:      
constant.DefaultMetadataStorageType,
+                       constant.MetadataServiceURLParamsPropertyName: 
paramsJSON,
+               },
+       }
+}
diff --git 
a/registry/servicediscovery/customizer/protocol_ports_metadata_customizer.go 
b/registry/servicediscovery/customizer/protocol_ports_metadata_customizer.go
index db88727fe..aa49ca664 100644
--- a/registry/servicediscovery/customizer/protocol_ports_metadata_customizer.go
+++ b/registry/servicediscovery/customizer/protocol_ports_metadata_customizer.go
@@ -46,7 +46,12 @@ func (p *ProtocolPortsMetadataCustomizer) GetPriority() int {
        return 0
 }
 
-// Customize put the the string like [{"protocol": "dubbo", "port": 123}] into 
instance's metadata
+// Customize writes the exported service endpoints into the instance metadata
+// under ServiceInstanceEndpoints ("dubbo.endpoints"). The URLs come from
+// metadata.GetMetadataService().GetExportedServiceURLs(); it returns without
+// writing when the list is empty (client side) or on error. URLs with an empty
+// protocol are skipped and unparsable ports are recorded as 0, then the
+// endpoints JSON overwrites the key.
 func (p *ProtocolPortsMetadataCustomizer) Customize(instance 
registry.ServiceInstance) {
        list, err := metadata.GetMetadataService().GetExportedServiceURLs()
        if err != nil {
@@ -75,6 +80,7 @@ func (p *ProtocolPortsMetadataCustomizer) Customize(instance 
registry.ServiceIns
 }
 
 // endpointsStr convert the map to json like [{"protocol": "dubbo", "port": 
123}]
+// It returns "" when the map is empty or the marshaling fails.
 func endpointsStr(protocolMap map[string]int) string {
        if len(protocolMap) == 0 {
                return ""
diff --git 
a/registry/servicediscovery/customizer/protocol_ports_metadata_customizer_test.go
 
b/registry/servicediscovery/customizer/protocol_ports_metadata_customizer_test.go
new file mode 100644
index 000000000..a86026726
--- /dev/null
+++ 
b/registry/servicediscovery/customizer/protocol_ports_metadata_customizer_test.go
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package customizer
+
+import (
+       "encoding/json"
+       "testing"
+)
+
+import (
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common"
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+       "dubbo.apache.org/dubbo-go/v3/metadata"
+       "dubbo.apache.org/dubbo-go/v3/registry"
+)
+
+func TestProtocolPortsMetadataCustomizerGetPriority(t *testing.T) {
+       p := &ProtocolPortsMetadataCustomizer{}
+       assert.Equal(t, 0, p.GetPriority())
+}
+
+// TestProtocolPortsCustomizeEmptyList verifies that no endpoints are written
+// when there are no exported service URLs (client side).
+func TestProtocolPortsCustomizeEmptyList(t *testing.T) {
+       p := &ProtocolPortsMetadataCustomizer{}
+       ins := &registry.DefaultServiceInstance{}
+       p.Customize(ins)
+       _, ok := ins.GetMetadata()[constant.ServiceInstanceEndpoints]
+       assert.False(t, ok, "endpoints should not be written for an empty 
exported URL list")
+}
+
+// TestProtocolPortsCustomizeWithURLs verifies that endpoints are derived from
+// the exported service URLs and written as a JSON array.
+func TestProtocolPortsCustomizeWithURLs(t *testing.T) {
+       urlDubbo := newEndpointTestURL("dubbo", "20880")
+       urlTri := newEndpointTestURL("tri", "50051")
+       metadata.AddService("protocol-ports-test", urlDubbo)
+       metadata.AddService("protocol-ports-test", urlTri)
+       t.Cleanup(func() {
+               metadata.RemoveService("protocol-ports-test", urlDubbo)
+               metadata.RemoveService("protocol-ports-test", urlTri)
+       })
+
+       p := &ProtocolPortsMetadataCustomizer{}
+       ins := &registry.DefaultServiceInstance{}
+       p.Customize(ins)
+
+       str := ins.GetMetadata()[constant.ServiceInstanceEndpoints]
+       assert.NotEmpty(t, str)
+       var endpoints []registry.Endpoint
+       require.NoError(t, json.Unmarshal([]byte(str), &endpoints))
+       assert.Len(t, endpoints, 2)
+
+       got := make(map[string]int)
+       for _, e := range endpoints {
+               got[e.Protocol] = e.Port
+       }
+       assert.Equal(t, 20880, got["dubbo"])
+       assert.Equal(t, 50051, got["tri"])
+}
+
+// TestProtocolPortsCustomizeSkipsEmptyProtocol verifies that URLs with an 
empty
+// protocol are skipped and do not appear in the endpoints.
+func TestProtocolPortsCustomizeSkipsEmptyProtocol(t *testing.T) {
+       urlNoProtocol := newEndpointTestURL("", "20880")
+       urlDubbo := newEndpointTestURL("dubbo", "20881")
+       metadata.AddService("protocol-ports-skip", urlNoProtocol)
+       metadata.AddService("protocol-ports-skip", urlDubbo)
+       t.Cleanup(func() {
+               metadata.RemoveService("protocol-ports-skip", urlNoProtocol)
+               metadata.RemoveService("protocol-ports-skip", urlDubbo)
+       })
+
+       p := &ProtocolPortsMetadataCustomizer{}
+       ins := &registry.DefaultServiceInstance{}
+       p.Customize(ins)
+
+       str := ins.GetMetadata()[constant.ServiceInstanceEndpoints]
+       var endpoints []registry.Endpoint
+       require.NoError(t, json.Unmarshal([]byte(str), &endpoints))
+       assert.Len(t, endpoints, 1, "URL with empty protocol should be skipped")
+       assert.Equal(t, "dubbo", endpoints[0].Protocol)
+       assert.Equal(t, 20881, endpoints[0].Port)
+}
+
+// TestProtocolPortsCustomizeUnparsablePort verifies that an unparsable port is
+// recorded as 0 (the endpoint is still kept) and does not abort the whole 
write.
+func TestProtocolPortsCustomizeUnparsablePort(t *testing.T) {
+       urlBadPort := newEndpointTestURL("dubbo", "not-a-number")
+       urlTri := newEndpointTestURL("tri", "50051")
+       metadata.AddService("protocol-ports-badport", urlBadPort)
+       metadata.AddService("protocol-ports-badport", urlTri)
+       t.Cleanup(func() {
+               metadata.RemoveService("protocol-ports-badport", urlBadPort)
+               metadata.RemoveService("protocol-ports-badport", urlTri)
+       })
+
+       p := &ProtocolPortsMetadataCustomizer{}
+       ins := &registry.DefaultServiceInstance{}
+       p.Customize(ins)
+
+       str := ins.GetMetadata()[constant.ServiceInstanceEndpoints]
+       var endpoints []registry.Endpoint
+       require.NoError(t, json.Unmarshal([]byte(str), &endpoints))
+       assert.Len(t, endpoints, 2)
+
+       ports := make(map[string]int)
+       for _, e := range endpoints {
+               ports[e.Protocol] = e.Port
+       }
+       assert.Equal(t, 0, ports["dubbo"], "unparsable port should be recorded 
as 0")
+       assert.Equal(t, 50051, ports["tri"], "other endpoints should still be 
written")
+}
+
+func TestEndpointsStrEmpty(t *testing.T) {
+       assert.Empty(t, endpointsStr(map[string]int{}))
+       assert.Empty(t, endpointsStr(nil))
+}
+
+func TestEndpointsStrNormal(t *testing.T) {
+       str := endpointsStr(map[string]int{"dubbo": 123})
+       var endpoints []registry.Endpoint
+       require.NoError(t, json.Unmarshal([]byte(str), &endpoints))
+       assert.Len(t, endpoints, 1)
+       assert.Equal(t, "dubbo", endpoints[0].Protocol)
+       assert.Equal(t, 123, endpoints[0].Port)
+}
+
+// newEndpointTestURL builds a URL with the given protocol and port for 
testing.
+func newEndpointTestURL(protocol, port string) *common.URL {
+       return common.NewURLWithOptions(
+               common.WithInterface("org.example.TestService"),
+               common.WithProtocol(protocol),
+               common.WithPort(port),
+       )
+}

Reply via email to