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 := ®istry.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 := ®istry.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 ®istry.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 := ®istry.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 := ®istry.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 := ®istry.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 := ®istry.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),
+ )
+}