This is an automated email from the ASF dual-hosted git repository.
alexstocks pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git
The following commit(s) were added to refs/heads/develop by this push:
new ba176139c refactor(client): remove config compat layer, use global
types directly (#3232)
ba176139c is described below
commit ba176139c13a31ae31466ec15c38b4a734137e1b
Author: nanjiek <[email protected]>
AuthorDate: Mon Mar 16 13:04:56 2026 +0800
refactor(client): remove config compat layer, use global types directly
(#3232)
* remove the config package from package client
* fix(client): fail fast on invalid registry and method config
* restore WithMethod in Server
* fix lint of action_test
* refactor: split processURL to reduce cognitive complexity
---
client/action.go | 113 +++++++++++++++++++++++++++---------------
client/action_test.go | 129 ++++++++++++++++++++++++++++++++++++++++++++++++
client/client.go | 28 +++++++++--
client/client_test.go | 25 ++++++++++
client/compat.go | 81 ------------------------------
client/options.go | 106 ++++++++++++---------------------------
client/options_test.go | 96 +++++++++++++++++++++++++++++------
global/config_test.go | 1 +
internal/config.go | 55 +++++++++++++++++++--
internal/config_test.go | 60 ++++++++++++++++++++--
server/action.go | 6 ++-
server/action_test.go | 21 ++++++++
server/options.go | 33 +++++++++++++
server/options_test.go | 81 ++++++++++++++++++++++++++++++
14 files changed, 609 insertions(+), 226 deletions(-)
diff --git a/client/action.go b/client/action.go
index 75e95a6c1..2b9aca347 100644
--- a/client/action.go
+++ b/client/action.go
@@ -40,9 +40,9 @@ import (
commonCfg "dubbo.apache.org/dubbo-go/v3/common/config"
"dubbo.apache.org/dubbo-go/v3/common/constant"
"dubbo.apache.org/dubbo-go/v3/common/extension"
- "dubbo.apache.org/dubbo-go/v3/config"
"dubbo.apache.org/dubbo-go/v3/global"
"dubbo.apache.org/dubbo-go/v3/graceful_shutdown"
+ "dubbo.apache.org/dubbo-go/v3/internal"
"dubbo.apache.org/dubbo-go/v3/protocol/base"
"dubbo.apache.org/dubbo-go/v3/protocol/protocolwrapper"
"dubbo.apache.org/dubbo-go/v3/proxy"
@@ -178,7 +178,7 @@ func (refOpts *ReferenceOptions) refer(srv
common.RPCService, info *ClientInfo)
updateOrCreateMeshURL(refOpts)
// retrieving urls from config, and appending the urls to refOpts.urls
- urls, err := processURL(ref, refOpts.registriesCompat, cfgURL)
+ urls, err := processURL(ref, refOpts.Registries, cfgURL)
if err != nil {
panic(err)
}
@@ -209,51 +209,82 @@ func (refOpts *ReferenceOptions) refer(srv
common.RPCService, info *ClientInfo)
graceful_shutdown.RegisterProtocol(ref.Protocol)
}
-func processURL(ref *global.ReferenceConfig, regsCompat
map[string]*config.RegistryConfig, cfgURL *common.URL) ([]*common.URL, error) {
+func processURL(ref *global.ReferenceConfig, registries
map[string]*global.RegistryConfig, cfgURL *common.URL) ([]*common.URL, error) {
+ if ref.URL != "" {
+ return processUserSpecifiedURLs(ref, cfgURL)
+ }
+
+ return loadRegistryURLs(ref, registries, cfgURL)
+}
+
+func processUserSpecifiedURLs(ref *global.ReferenceConfig, cfgURL *common.URL)
([]*common.URL, error) {
+ /*
+ Two types of URL are allowed for refOpts.URL:
+ 1. direct url: server IP, that is, no need for a
registry anymore
+ 2. registry url
+ They will be handled in different ways:
+ For example, we have a direct url and a registry url:
+ 1. "tri://localhost:10000" is a direct url
+ 2. "registry://localhost:2181" is a registry url.
+ Then, refOpts.URL looks like a string separated by semicolon:
"tri://localhost:10000;registry://localhost:2181".
+ The result of urlStrings is a string array:
[]string{"tri://localhost:10000", "registry://localhost:2181"}.
+ */
var urls []*common.URL
- if ref.URL != "" { // use user-specific urls
- /*
- Two types of URL are allowed for refOpts.URL:
- 1. direct url: server IP, that is, no need for
a registry anymore
- 2. registry url
- They will be handled in different ways:
- For example, we have a direct url and a registry url:
- 1. "tri://localhost:10000" is a direct url
- 2. "registry://localhost:2181" is a registry
url.
- Then, refOpts.URL looks like a string separated by
semicolon: "tri://localhost:10000;registry://localhost:2181".
- The result of urlStrings is a string array:
[]string{"tri://localhost:10000", "registry://localhost:2181"}.
- */
- urlStrings := gxstrings.RegSplit(ref.URL, "\\s*[;]+\\s*")
- for _, urlStr := range urlStrings {
- serviceURL, err := common.NewURL(urlStr,
common.WithProtocol(ref.Protocol))
- if err != nil {
- return nil, fmt.Errorf("url configuration
error, please check your configuration, user specified URL %v refer error,
error message is %v ", urlStr, err.Error())
- }
- if serviceURL.Protocol == constant.RegistryProtocol {
// serviceURL in this branch is a registry protocol
- serviceURL.SubURL = cfgURL
- urls = append(urls, serviceURL)
- } else { // serviceURL in this branch is the target
endpoint IP address
- if serviceURL.Path == "" {
- serviceURL.Path = "/" +
ref.InterfaceName
- }
- // replace params of serviceURL with params of
cfgUrl
- // other stuff, e.g. IP, port, etc., are same
as serviceURL
- newURL := serviceURL.MergeURL(cfgURL)
- newURL.AddParam("peer", "true")
- urls = append(urls, newURL)
- }
- }
- } else { // use registry configs
- urls = config.LoadRegistries(ref.RegistryIDs, regsCompat,
common.CONSUMER)
- // set url to regURLs
- for _, regURL := range urls {
- regURL.SubURL = cfgURL
+ urlStrings := gxstrings.RegSplit(ref.URL, "\\s*[;]+\\s*")
+
+ for _, urlStr := range urlStrings {
+ serviceURL, err := common.NewURL(urlStr,
common.WithProtocol(ref.Protocol))
+ if err != nil {
+ return nil, fmt.Errorf("url configuration error,
please check your configuration, user specified URL %v refer error, error
message is %v ", urlStr, err.Error())
}
+
+ urls = append(urls, buildReferenceURL(serviceURL, ref, cfgURL))
}
+
return urls, nil
}
+func buildReferenceURL(serviceURL *common.URL, ref *global.ReferenceConfig,
cfgURL *common.URL) *common.URL {
+ if serviceURL.Protocol == constant.RegistryProtocol {
+ serviceURL.SubURL = cfgURL
+ return serviceURL
+ }
+
+ if serviceURL.Path == "" {
+ serviceURL.Path = "/" + ref.InterfaceName
+ }
+
+ // replace params of serviceURL with params of cfgUrl
+ // other stuff, e.g. IP, port, etc., are same as serviceURL
+ newURL := serviceURL.MergeURL(cfgURL)
+ newURL.AddParam("peer", "true")
+ return newURL
+}
+
+func loadRegistryURLs(ref *global.ReferenceConfig, registries
map[string]*global.RegistryConfig, cfgURL *common.URL) ([]*common.URL, error) {
+ urls, err := internal.LoadRegistries(ref.RegistryIDs, registries,
common.CONSUMER)
+ if err != nil {
+ return nil, err
+ }
+ if len(urls) == 0 {
+ return nil, fmt.Errorf("no registry urls available for registry
ids %v", ref.RegistryIDs)
+ }
+
+ attachSubURL(urls, cfgURL)
+ return urls, nil
+}
+
+func attachSubURL(urls []*common.URL, cfgURL *common.URL) {
+ for _, regURL := range urls {
+ regURL.SubURL = cfgURL
+ }
+}
+
func buildInvoker(urls []*common.URL, ref *global.ReferenceConfig)
(base.Invoker, error) {
+ if len(urls) == 0 {
+ return nil, fmt.Errorf("no urls available to build invoker")
+ }
+
var (
invoker base.Invoker
regURL *common.URL
@@ -355,7 +386,7 @@ func (refOpts *ReferenceOptions) GetProxy() *proxy.Proxy {
func (refOpts *ReferenceOptions) getURLMap() url.Values {
ref := refOpts.Reference
- app := refOpts.applicationCompat
+ app := refOpts.Application
metrics := refOpts.Metrics
tracing := refOpts.Otel.TracingConfig
diff --git a/client/action_test.go b/client/action_test.go
index bb2493c88..fb2834c75 100644
--- a/client/action_test.go
+++ b/client/action_test.go
@@ -28,6 +28,7 @@ import (
)
import (
+ "dubbo.apache.org/dubbo-go/v3/common"
"dubbo.apache.org/dubbo-go/v3/common/constant"
"dubbo.apache.org/dubbo-go/v3/global"
)
@@ -97,3 +98,131 @@ func TestUpdateOrCreateMeshURL(t *testing.T) {
})
})
}
+
+func TestProcessURLPropagatesRegistryError(t *testing.T) {
+ ref := &global.ReferenceConfig{
+ InterfaceName: "com.example.Service",
+ RegistryIDs: []string{"bad"},
+ }
+ cfgURL := common.NewURLWithOptions(common.WithPath(ref.InterfaceName))
+ registries := map[string]*global.RegistryConfig{
+ "bad": {
+ Protocol: "mock",
+ Address: "127.0.0.1:bad",
+ },
+ }
+
+ urls, err := processURL(ref, registries, cfgURL)
+ require.Nil(t, urls)
+ require.Error(t, err)
+ require.Contains(t, err.Error(), `registry id "bad" url is invalid`)
+}
+
+func TestProcessURLRejectsEmptyRegistryURLs(t *testing.T) {
+ ref := &global.ReferenceConfig{
+ InterfaceName: "com.example.Service",
+ RegistryIDs: []string{"empty"},
+ }
+ cfgURL := common.NewURLWithOptions(common.WithPath(ref.InterfaceName))
+ registries := map[string]*global.RegistryConfig{
+ "empty": {
+ Protocol: "mock",
+ Address: constant.NotAvailable,
+ },
+ }
+
+ urls, err := processURL(ref, registries, cfgURL)
+ require.Nil(t, urls)
+ require.Error(t, err)
+ require.Contains(t, err.Error(), "no registry urls available")
+}
+
+func TestProcessURLWithDirectUserURL(t *testing.T) {
+ ref := &global.ReferenceConfig{
+ InterfaceName: "com.example.Service",
+ Protocol: constant.TriProtocol,
+ URL: "tri://localhost:20000",
+ }
+ cfgURL := common.NewURLWithOptions(
+ common.WithPath(ref.InterfaceName),
+ common.WithParamsValue(constant.GroupKey, "test-group"),
+ )
+
+ urls, err := processURL(ref, nil, cfgURL)
+ require.NoError(t, err)
+ require.Len(t, urls, 1)
+ require.Equal(t, constant.TriProtocol, urls[0].Protocol)
+ require.Equal(t, "/"+ref.InterfaceName, urls[0].Path)
+ require.Equal(t, "test-group", urls[0].GetParam(constant.GroupKey, ""))
+ require.Equal(t, "true", urls[0].GetParam("peer", ""))
+}
+
+func TestProcessURLWithMultipleDirectUserURLs(t *testing.T) {
+ ref := &global.ReferenceConfig{
+ InterfaceName: "com.example.Service",
+ Protocol: constant.TriProtocol,
+ URL: "tri://localhost:20000;tri://localhost:20001",
+ }
+ cfgURL := common.NewURLWithOptions(common.WithPath(ref.InterfaceName))
+
+ urls, err := processURL(ref, nil, cfgURL)
+ require.NoError(t, err)
+ require.Len(t, urls, 2)
+ require.Equal(t, constant.TriProtocol, urls[0].Protocol)
+ require.Equal(t, "true", urls[0].GetParam("peer", ""))
+ require.Equal(t, constant.TriProtocol, urls[1].Protocol)
+ require.Equal(t, "true", urls[1].GetParam("peer", ""))
+}
+
+func TestProcessURLRejectsInvalidUserURL(t *testing.T) {
+ ref := &global.ReferenceConfig{
+ InterfaceName: "com.example.Service",
+ Protocol: constant.TriProtocol,
+ URL: "://bad-url",
+ }
+ cfgURL := common.NewURLWithOptions(common.WithPath(ref.InterfaceName))
+
+ urls, err := processURL(ref, nil, cfgURL)
+ require.Nil(t, urls)
+ require.Error(t, err)
+ require.Contains(t, err.Error(), "url configuration error")
+}
+
+func TestBuildReferenceURLWithRegistryProtocol(t *testing.T) {
+ ref := &global.ReferenceConfig{InterfaceName: "com.example.Service"}
+ cfgURL := common.NewURLWithOptions(common.WithPath(ref.InterfaceName))
+ serviceURL :=
common.NewURLWithOptions(common.WithProtocol(constant.RegistryProtocol))
+
+ result := buildReferenceURL(serviceURL, ref, cfgURL)
+
+ require.Same(t, serviceURL, result)
+ require.Same(t, cfgURL, result.SubURL)
+}
+
+func TestLoadRegistryURLsAssignsSubURL(t *testing.T) {
+ ref := &global.ReferenceConfig{
+ InterfaceName: "com.example.Service",
+ RegistryIDs: []string{"valid"},
+ }
+ cfgURL := common.NewURLWithOptions(common.WithPath(ref.InterfaceName))
+ registries := map[string]*global.RegistryConfig{
+ "valid": {
+ Protocol: "zookeeper",
+ Address: "127.0.0.1:2181",
+ },
+ }
+
+ urls, err := loadRegistryURLs(ref, registries, cfgURL)
+ require.NoError(t, err)
+ require.NotEmpty(t, urls)
+ for _, regURL := range urls {
+ require.Same(t, cfgURL, regURL.SubURL)
+ }
+}
+
+func TestBuildInvokerRejectsEmptyURLs(t *testing.T) {
+ invoker, err := buildInvoker(nil, &global.ReferenceConfig{})
+ require.Nil(t, invoker)
+ require.Error(t, err)
+ require.Contains(t, err.Error(), "no urls available")
+}
diff --git a/client/client.go b/client/client.go
index e31fdc7f2..e443e5da6 100644
--- a/client/client.go
+++ b/client/client.go
@@ -27,6 +27,7 @@ import (
"dubbo.apache.org/dubbo-go/v3/common"
"dubbo.apache.org/dubbo-go/v3/common/constant"
"dubbo.apache.org/dubbo-go/v3/filter/generic"
+ "dubbo.apache.org/dubbo-go/v3/global"
"dubbo.apache.org/dubbo-go/v3/metadata"
"dubbo.apache.org/dubbo-go/v3/protocol/base"
"dubbo.apache.org/dubbo-go/v3/protocol/invocation"
@@ -187,15 +188,10 @@ func (cli *Client) DialWithDefinition(interfaceName
string, definition *ClientDe
}
func (cli *Client) dial(interfaceName string, info *ClientInfo, srv any, opts
...ReferenceOption) (*Connection, error) {
- if err := metadata.InitRegistryMetadataReport(cli.cliOpts.Registries);
err != nil {
- return nil, err
- }
newRefOpts := defaultReferenceOptions()
finalOpts := []ReferenceOption{
setReference(cli.cliOpts.overallReference),
setApplication(cli.cliOpts.Application),
- setApplicationCompat(cli.cliOpts.applicationCompat),
- setRegistriesCompat(cli.cliOpts.registriesCompat),
setRegistries(cli.cliOpts.Registries),
setConsumer(cli.cliOpts.Consumer),
setShutdown(cli.cliOpts.Shutdown),
@@ -211,6 +207,11 @@ func (cli *Client) dial(interfaceName string, info
*ClientInfo, srv any, opts ..
if err := newRefOpts.init(finalOpts...); err != nil {
return nil, err
}
+ effectiveRegistries :=
filterRegistriesByIDs(newRefOpts.Reference.RegistryIDs, newRefOpts.Registries)
+ if err := metadata.InitRegistryMetadataReport(effectiveRegistries); err
!= nil {
+ return nil, err
+ }
+ newRefOpts.Registries = effectiveRegistries
if info != nil {
newRefOpts.ReferWithInfo(info)
@@ -223,6 +224,23 @@ func (cli *Client) dial(interfaceName string, info
*ClientInfo, srv any, opts ..
return &Connection{refOpts: newRefOpts}, nil
}
+func filterRegistriesByIDs(ids []string, regs
map[string]*global.RegistryConfig) map[string]*global.RegistryConfig {
+ if len(regs) == 0 {
+ return regs
+ }
+ if len(ids) == 0 || (len(ids) == 1 && ids[0] == "") {
+ return regs
+ }
+
+ filtered := make(map[string]*global.RegistryConfig, len(ids))
+ for _, id := range ids {
+ if reg, ok := regs[id]; ok {
+ filtered[id] = reg
+ }
+ }
+ return filtered
+}
+
func generateInvocation(ctx context.Context, methodName string, reqs []any,
resp any, callType string, opts *CallOptions) (base.Invocation, error) {
var paramsRawVals []any
diff --git a/client/client_test.go b/client/client_test.go
index 4f9766f16..95d2e5ea1 100644
--- a/client/client_test.go
+++ b/client/client_test.go
@@ -31,6 +31,7 @@ import (
import (
"dubbo.apache.org/dubbo-go/v3/common"
"dubbo.apache.org/dubbo-go/v3/common/constant"
+ "dubbo.apache.org/dubbo-go/v3/global"
"dubbo.apache.org/dubbo-go/v3/protocol/base"
"dubbo.apache.org/dubbo-go/v3/protocol/result"
)
@@ -241,3 +242,27 @@ func requireCallType(t *testing.T, inv base.Invocation,
callType string) {
require.True(t, ok)
require.Equal(t, callType, attr)
}
+
+func TestFilterRegistriesByIDs(t *testing.T) {
+ regs := map[string]*global.RegistryConfig{
+ "r1": {Protocol: "mock", Address: "127.0.0.1:2181"},
+ "r2": {Protocol: "mock", Address: "127.0.0.2:2181"},
+ }
+
+ filtered := filterRegistriesByIDs([]string{"r2"}, regs)
+ require.Len(t, filtered, 1)
+ require.Contains(t, filtered, "r2")
+ require.NotContains(t, filtered, "r1")
+}
+
+func TestFilterRegistriesByIDsReturnsAllWhenIDsEmpty(t *testing.T) {
+ regs := map[string]*global.RegistryConfig{
+ "r1": {Protocol: "mock", Address: "127.0.0.1:2181"},
+ "r2": {Protocol: "mock", Address: "127.0.0.2:2181"},
+ }
+
+ filtered := filterRegistriesByIDs(nil, regs)
+ require.Len(t, filtered, 2)
+ require.Contains(t, filtered, "r1")
+ require.Contains(t, filtered, "r2")
+}
diff --git a/client/compat.go b/client/compat.go
deleted file mode 100644
index 3a91c9725..000000000
--- a/client/compat.go
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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 client
-
-import (
- "dubbo.apache.org/dubbo-go/v3/config"
- "dubbo.apache.org/dubbo-go/v3/global"
-)
-
-// these functions are used to resolve circular dependencies temporarily.
-// please refer to issue(https://github.com/apache/dubbo-go/issues/2377)
-// todo(DMwangnima): remove these functions when refactoring dubbo-go
-func compatApplicationConfig(c *global.ApplicationConfig)
*config.ApplicationConfig {
- return &config.ApplicationConfig{
- Organization: c.Organization,
- Name: c.Name,
- Module: c.Module,
- Group: c.Group,
- Version: c.Version,
- Owner: c.Owner,
- Environment: c.Environment,
- MetadataType: c.MetadataType,
- Tag: c.Tag,
- MetadataServicePort: c.MetadataServicePort,
- MetadataServiceProtocol: c.MetadataServiceProtocol,
- }
-}
-
-func compatRegistryConfig(c *global.RegistryConfig) *config.RegistryConfig {
- return &config.RegistryConfig{
- Protocol: c.Protocol,
- Timeout: c.Timeout,
- Group: c.Group,
- Namespace: c.Namespace,
- TTL: c.TTL,
- Address: c.Address,
- Username: c.Username,
- Password: c.Password,
- Simplified: c.Simplified,
- Preferred: c.Preferred,
- Zone: c.Zone,
- Weight: c.Weight,
- Params: c.Params,
- RegistryType: c.RegistryType,
- UseAsMetaReport: c.UseAsMetaReport,
- UseAsConfigCenter: c.UseAsConfigCenter,
- }
-}
-
-func compatMethodConfig(c *global.MethodConfig) *config.MethodConfig {
- return &config.MethodConfig{
- InterfaceId: c.InterfaceId,
- InterfaceName: c.InterfaceName,
- Name: c.Name,
- Retries: c.Retries,
- LoadBalance: c.LoadBalance,
- Weight: c.Weight,
- TpsLimitInterval: c.TpsLimitInterval,
- TpsLimitRate: c.TpsLimitRate,
- TpsLimitStrategy: c.TpsLimitStrategy,
- ExecuteLimit: c.ExecuteLimit,
- ExecuteLimitRejectedHandler: c.ExecuteLimitRejectedHandler,
- Sticky: c.Sticky,
- RequestTimeout: c.RequestTimeout,
- }
-}
diff --git a/client/options.go b/client/options.go
index f837b1501..e2d6f9b3f 100644
--- a/client/options.go
+++ b/client/options.go
@@ -18,6 +18,7 @@
package client
import (
+ "fmt"
"strconv"
"time"
)
@@ -30,9 +31,9 @@ import (
"dubbo.apache.org/dubbo-go/v3/common"
commonCfg "dubbo.apache.org/dubbo-go/v3/common/config"
"dubbo.apache.org/dubbo-go/v3/common/constant"
- "dubbo.apache.org/dubbo-go/v3/config"
"dubbo.apache.org/dubbo-go/v3/global"
"dubbo.apache.org/dubbo-go/v3/graceful_shutdown"
+ "dubbo.apache.org/dubbo-go/v3/internal"
"dubbo.apache.org/dubbo-go/v3/protocol"
"dubbo.apache.org/dubbo-go/v3/protocol/base"
"dubbo.apache.org/dubbo-go/v3/proxy"
@@ -57,10 +58,6 @@ type ReferenceOptions struct {
urls []*common.URL
metaDataType string
info *ClientInfo
-
- methodsCompat []*config.MethodConfig
- applicationCompat *config.ApplicationConfig
- registriesCompat map[string]*config.RegistryConfig
}
func defaultReferenceOptions() *ReferenceOptions {
@@ -86,7 +83,7 @@ func (refOpts *ReferenceOptions) init(opts
...ReferenceOption) error {
refConf := refOpts.Reference
- app := refOpts.applicationCompat
+ app := refOpts.Application
if app != nil {
refOpts.metaDataType = app.MetadataType
if refConf.Group == "" {
@@ -98,12 +95,11 @@ func (refOpts *ReferenceOptions) init(opts
...ReferenceOption) error {
}
// init method
- methods := refConf.MethodsConfig
- if length := len(methods); length > 0 {
- refOpts.methodsCompat = make([]*config.MethodConfig, length)
- for i, method := range methods {
- refOpts.methodsCompat[i] = compatMethodConfig(method)
- if err := refOpts.methodsCompat[i].Init(); err != nil {
+ if refConf.MethodsConfig == nil {
+ refConf.MethodsConfig = make([]*global.MethodConfig, 0)
+ } else {
+ for _, method := range refConf.MethodsConfig {
+ if err := internal.ValidateMethodConfig(method); err !=
nil {
return err
}
}
@@ -115,36 +111,18 @@ func (refOpts *ReferenceOptions) init(opts
...ReferenceOption) error {
}
// init registries
- // convert Registries to registriesCompat
if len(refOpts.Registries) > 0 {
- if refOpts.registriesCompat == nil {
- refOpts.registriesCompat =
make(map[string]*config.RegistryConfig)
- }
- for id, reg := range refOpts.Registries {
- refOpts.registriesCompat[id] = compatRegistryConfig(reg)
- if err := refOpts.registriesCompat[id].Init(); err !=
nil {
- return err
- }
- }
- }
-
- if len(refOpts.registriesCompat) > 0 {
- regs := refOpts.registriesCompat
+ regs := refOpts.Registries
if len(refConf.RegistryIDs) <= 0 {
- refConf.RegistryIDs = make([]string, len(regs))
+ refConf.RegistryIDs = make([]string, 0, len(regs))
for key := range regs {
refConf.RegistryIDs =
append(refConf.RegistryIDs, key)
}
}
refConf.RegistryIDs =
commonCfg.TranslateIds(refConf.RegistryIDs)
-
- newRegs := make(map[string]*config.RegistryConfig)
- for _, id := range refConf.RegistryIDs {
- if reg, ok := regs[id]; ok {
- newRegs[id] = reg
- }
+ if err := validateRegistryIDs(refConf.RegistryIDs, regs); err
!= nil {
+ return err
}
- refOpts.registriesCompat = newRegs
}
// init protocol
@@ -447,14 +425,15 @@ func WithMeshProviderPort(port int) ReferenceOption {
}
}
-func WithMethod(opts ...config.MethodOption) ReferenceOption {
- regOpts := config.NewMethodOptions(opts...)
-
+func WithMethod(method *global.MethodConfig) ReferenceOption {
return func(opts *ReferenceOptions) {
- if len(opts.Reference.MethodsConfig) == 0 {
+ if method == nil {
+ return
+ }
+ if opts.Reference.MethodsConfig == nil {
opts.Reference.MethodsConfig =
make([]*global.MethodConfig, 0)
}
- opts.Reference.MethodsConfig =
append(opts.Reference.MethodsConfig, regOpts.Method)
+ opts.Reference.MethodsConfig =
append(opts.Reference.MethodsConfig, method)
}
}
@@ -482,18 +461,6 @@ func setInterfaceName(interfaceName string)
ReferenceOption {
}
}
-func setApplicationCompat(app *config.ApplicationConfig) ReferenceOption {
- return func(opts *ReferenceOptions) {
- opts.applicationCompat = app
- }
-}
-
-func setRegistriesCompat(regs map[string]*config.RegistryConfig)
ReferenceOption {
- return func(opts *ReferenceOptions) {
- opts.registriesCompat = regs
- }
-}
-
func setConsumer(consumer *global.ConsumerConfig) ReferenceOption {
return func(opts *ReferenceOptions) {
opts.Consumer = consumer
@@ -556,9 +523,7 @@ type ClientOptions struct {
TLS *global.TLSConfig
Protocols map[string]*global.ProtocolConfig
- overallReference *global.ReferenceConfig
- applicationCompat *config.ApplicationConfig
- registriesCompat map[string]*config.RegistryConfig
+ overallReference *global.ReferenceConfig
}
func defaultClientOptions() *ClientOptions {
@@ -585,34 +550,18 @@ func (cliOpts *ClientOptions) init(opts ...ClientOption)
error {
consumerConf := cliOpts.Consumer
- // init application
- application := cliOpts.Application
- if application != nil {
- cliOpts.applicationCompat = compatApplicationConfig(application)
- if err := cliOpts.applicationCompat.Init(); err != nil {
- return err
- }
- }
-
// init registries
regs := cliOpts.Registries
- if regs != nil {
- cliOpts.registriesCompat =
make(map[string]*config.RegistryConfig)
+ if len(regs) > 0 {
if len(consumerConf.RegistryIDs) <= 0 {
- consumerConf.RegistryIDs = make([]string, len(regs))
+ consumerConf.RegistryIDs = make([]string, 0, len(regs))
for key := range regs {
consumerConf.RegistryIDs =
append(consumerConf.RegistryIDs, key)
}
}
consumerConf.RegistryIDs =
commonCfg.TranslateIds(consumerConf.RegistryIDs)
-
- for _, id := range consumerConf.RegistryIDs {
- if reg, ok := regs[id]; ok {
- cliOpts.registriesCompat[id] =
compatRegistryConfig(reg)
- if err := cliOpts.registriesCompat[id].Init();
err != nil {
- return err
- }
- }
+ if err := validateRegistryIDs(consumerConf.RegistryIDs, regs);
err != nil {
+ return err
}
}
@@ -1017,6 +966,15 @@ func newDefaultCallOptions() *CallOptions {
return &CallOptions{}
}
+func validateRegistryIDs(ids []string, regs map[string]*global.RegistryConfig)
error {
+ for _, id := range ids {
+ if _, ok := regs[id]; !ok {
+ return fmt.Errorf("registry id %q not found", id)
+ }
+ }
+ return nil
+}
+
// WithCallRequestTimeout the maximum waiting time for one specific call, only
works for 'tri' and 'dubbo' protocol
func WithCallRequestTimeout(timeout time.Duration) CallOption {
return func(opts *CallOptions) {
diff --git a/client/options_test.go b/client/options_test.go
index a05660eee..963d3696e 100644
--- a/client/options_test.go
+++ b/client/options_test.go
@@ -130,9 +130,7 @@ func TestWithClientRegistry(t *testing.T) {
reg, ok :=
cli.cliOpts.Registries[constant.ZookeeperKey]
assert.True(t, ok)
assert.Equal(t, "127.0.0.1:2181", reg.Address)
- regCompat, ok :=
cli.cliOpts.registriesCompat[constant.ZookeeperKey]
- assert.True(t, ok)
- assert.Equal(t, "127.0.0.1:2181",
regCompat.Address)
+ assert.Equal(t,
[]string{constant.ZookeeperKey}, cli.cliOpts.Consumer.RegistryIDs)
},
},
{
@@ -149,9 +147,7 @@ func TestWithClientRegistry(t *testing.T) {
reg, ok := cli.cliOpts.Registries["zk"]
assert.True(t, ok)
assert.Equal(t, "127.0.0.1:2181", reg.Address)
- regCompat, ok :=
cli.cliOpts.registriesCompat["zk"]
- assert.True(t, ok)
- assert.Equal(t, "127.0.0.1:2181",
regCompat.Address)
+ assert.Equal(t, []string{"zk"},
cli.cliOpts.Consumer.RegistryIDs)
},
},
{
@@ -170,18 +166,34 @@ func TestWithClientRegistry(t *testing.T) {
},
verify: func(t *testing.T, cli *Client, err error) {
require.NoError(t, err)
- zkReg, ok :=
cli.cliOpts.Registries[constant.ZookeeperKey]
- assert.True(t, ok)
- assert.Equal(t, "127.0.0.1:2181", zkReg.Address)
ncReg, ok :=
cli.cliOpts.Registries["nacos_test"]
assert.True(t, ok)
assert.Equal(t, "127.0.0.1:8848", ncReg.Address)
-
- _, ok =
cli.cliOpts.registriesCompat[constant.ZookeeperKey]
- assert.False(t, ok)
- ncCompat, ok :=
cli.cliOpts.registriesCompat["nacos_test"]
+ assert.Len(t, cli.cliOpts.Registries, 2)
+ _, ok =
cli.cliOpts.Registries[constant.ZookeeperKey]
assert.True(t, ok)
- assert.Equal(t, "127.0.0.1:8848",
ncCompat.Address)
+ assert.Equal(t, []string{"nacos_test"},
cli.cliOpts.Consumer.RegistryIDs)
+ },
+ },
+ {
+ desc: "config multiple registries without setting
RegistryIds",
+ opts: []ClientOption{
+ WithClientRegistry(
+ registry.WithZookeeper(),
+ registry.WithAddress("127.0.0.1:2181"),
+ ),
+ WithClientRegistry(
+ registry.WithID("nacos_test"),
+ registry.WithNacos(),
+ registry.WithAddress("127.0.0.1:8848"),
+ ),
+ },
+ verify: func(t *testing.T, cli *Client, err error) {
+ require.NoError(t, err)
+ assert.Len(t, cli.cliOpts.Registries, 2)
+ assert.Contains(t, cli.cliOpts.Registries,
constant.ZookeeperKey)
+ assert.Contains(t, cli.cliOpts.Registries,
"nacos_test")
+ assert.ElementsMatch(t,
[]string{constant.ZookeeperKey, "nacos_test"}, cli.cliOpts.Consumer.RegistryIDs)
},
},
}
@@ -1225,3 +1237,59 @@ func TestInitWithConsumer(t *testing.T) {
t.Errorf("fields not copied as expected: %+v", ref)
}
}
+
+func TestClientOptionsInitKeepsOriginalRegistries(t *testing.T) {
+ cliOpts := &ClientOptions{
+ Consumer: &global.ConsumerConfig{
+ RegistryIDs: []string{"r1"},
+ },
+ Registries: map[string]*global.RegistryConfig{
+ "r1": {Protocol: "mock", Address: "127.0.0.1:2181"},
+ "r2": {Protocol: "mock", Address: "127.0.0.2:2181"},
+ },
+ overallReference: &global.ReferenceConfig{},
+ }
+
+ err := cliOpts.init()
+ require.NoError(t, err)
+ assert.Len(t, cliOpts.Registries, 2)
+ assert.Contains(t, cliOpts.Registries, "r1")
+ assert.Contains(t, cliOpts.Registries, "r2")
+}
+
+func TestClientOptionsInitFailsOnMissingRegistryID(t *testing.T) {
+ cliOpts := &ClientOptions{
+ Consumer: &global.ConsumerConfig{
+ RegistryIDs: []string{"missing"},
+ },
+ Registries: map[string]*global.RegistryConfig{
+ "r1": {Protocol: "mock", Address: "127.0.0.1:2181"},
+ },
+ overallReference: &global.ReferenceConfig{},
+ }
+
+ err := cliOpts.init()
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), `registry id "missing" not found`)
+}
+
+func TestReferenceOptionsInitFailsOnMissingRegistryID(t *testing.T) {
+ refOpts := defaultReferenceOptions()
+ refOpts.Registries = map[string]*global.RegistryConfig{
+ "r1": {Protocol: "mock", Address: "127.0.0.1:2181"},
+ }
+
+ err := refOpts.init(WithRegistryIDs("missing"))
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), `registry id "missing" not found`)
+}
+
+func TestReferenceOptionsInitFailsOnInvalidMethodConfig(t *testing.T) {
+ refOpts := defaultReferenceOptions()
+ err := refOpts.init(WithMethod(&global.MethodConfig{
+ Name: "testMethod",
+ TpsLimitRate: "-1",
+ }))
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "tps.limit.rate")
+}
diff --git a/global/config_test.go b/global/config_test.go
index f9b547b6f..31314e5bf 100644
--- a/global/config_test.go
+++ b/global/config_test.go
@@ -1798,6 +1798,7 @@ func TestMethodConfigFields(t *testing.T) {
assert.Equal(t, "10s", method.RequestTimeout)
})
}
+
func TestMetricConfigClone(t *testing.T) {
t.Run("clone_metrics_config", func(t *testing.T) {
metrics := DefaultMetricsConfig()
diff --git a/internal/config.go b/internal/config.go
index 90ae62fff..0f3d286dc 100644
--- a/internal/config.go
+++ b/internal/config.go
@@ -21,6 +21,7 @@
package internal
import (
+ "fmt"
"net/url"
"strconv"
"strings"
@@ -33,16 +34,26 @@ import (
import (
"dubbo.apache.org/dubbo-go/v3/common"
"dubbo.apache.org/dubbo-go/v3/common/constant"
+ "dubbo.apache.org/dubbo-go/v3/common/extension"
"dubbo.apache.org/dubbo-go/v3/global"
)
-func LoadRegistries(registryIds []string, registries
map[string]*global.RegistryConfig, roleType common.RoleType) []*common.URL {
+func LoadRegistries(registryIds []string, registries
map[string]*global.RegistryConfig, roleType common.RoleType) ([]*common.URL,
error) {
var registryURLs []*common.URL
+ targetAll := len(registryIds) == 0 || (len(registryIds) == 1 &&
registryIds[0] == "")
+
+ if !targetAll {
+ for _, id := range registryIds {
+ if _, ok := registries[id]; !ok {
+ return nil, fmt.Errorf("registry id %q not
found", id)
+ }
+ }
+ }
for k, registryConf := range registries {
target := false
- if len(registryIds) == 0 || (len(registryIds) == 1 &&
registryIds[0] == "") {
+ if targetAll {
target = true
} else {
for _, tr := range registryIds {
@@ -56,8 +67,7 @@ func LoadRegistries(registryIds []string, registries
map[string]*global.Registry
if target {
urls, err := toURLs(registryConf, roleType)
if err != nil {
- logger.Errorf("The registry id: %s url is
invalid, error: %#v", k, err)
- continue
+ return nil, fmt.Errorf("registry id %q url is
invalid: %w", k, err)
}
for _, u := range urls {
@@ -72,7 +82,7 @@ func LoadRegistries(registryIds []string, registries
map[string]*global.Registry
}
}
- return registryURLs
+ return registryURLs, nil
}
func toURLs(registriesConfig *global.RegistryConfig, roleType common.RoleType)
([]*common.URL, error) {
@@ -161,3 +171,38 @@ func getUrlMap(registriesConfig *global.RegistryConfig,
roleType common.RoleType
func clientNameID(protocol, address string) string {
return strings.Join([]string{constant.RegistryConfigPrefix, protocol,
address}, "-")
}
+
+func ValidateMethodConfig(method *global.MethodConfig) error {
+ if method == nil {
+ return nil
+ }
+
+ qualifiedMethodName := method.InterfaceName + "#" + method.Name
+ if method.TpsLimitStrategy != "" {
+ if _, err :=
extension.GetTpsLimitStrategyCreator(method.TpsLimitStrategy); err != nil {
+ return err
+ }
+ }
+
+ if method.TpsLimitInterval != "" {
+ tpsLimitInterval, err :=
strconv.ParseInt(method.TpsLimitInterval, 0, 0)
+ if err != nil {
+ return fmt.Errorf("[MethodConfig] Cannot parse the
configuration tps.limit.interval for method %s, please check your
configuration", qualifiedMethodName)
+ }
+ if tpsLimitInterval < 0 {
+ return fmt.Errorf("[MethodConfig] The configuration
tps.limit.interval for %s must be positive, please check your configuration",
qualifiedMethodName)
+ }
+ }
+
+ if method.TpsLimitRate != "" {
+ tpsLimitRate, err := strconv.ParseInt(method.TpsLimitRate, 0, 0)
+ if err != nil {
+ return fmt.Errorf("[MethodConfig] Cannot parse the
configuration tps.limit.rate for method %s, please check your configuration",
qualifiedMethodName)
+ }
+ if tpsLimitRate < 0 {
+ return fmt.Errorf("[MethodConfig] The configuration
tps.limit.rate for method %s must be positive, please check your
configuration", qualifiedMethodName)
+ }
+ }
+
+ return nil
+}
diff --git a/internal/config_test.go b/internal/config_test.go
index 515786ebf..15fdcf7e8 100644
--- a/internal/config_test.go
+++ b/internal/config_test.go
@@ -61,7 +61,8 @@ func TestLoadRegistries_AllOrEmptyIDs(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- urls := LoadRegistries(tt.ids, registries,
common.CONSUMER)
+ urls, err := LoadRegistries(tt.ids, registries,
common.CONSUMER)
+ require.NoError(t, err)
require.Len(t, urls, 3)
counts := map[string]int{}
@@ -92,14 +93,15 @@ func TestLoadRegistries_FilteredIDs(t *testing.T) {
},
}
- urls := LoadRegistries([]string{"r1"}, registries, common.CONSUMER)
+ urls, err := LoadRegistries([]string{"r1"}, registries, common.CONSUMER)
+ require.NoError(t, err)
require.Len(t, urls, 1)
for _, u := range urls {
assert.Equal(t, "r1", u.GetParam(constant.RegistryIdKey, ""))
}
}
-func TestLoadRegistries_SkipInvalidURL(t *testing.T) {
+func TestLoadRegistries_InvalidURL(t *testing.T) {
registries := map[string]*global.RegistryConfig{
"bad": {
Protocol: "mock",
@@ -109,8 +111,25 @@ func TestLoadRegistries_SkipInvalidURL(t *testing.T) {
},
}
- urls := LoadRegistries([]string{"bad"}, registries, common.CONSUMER)
- assert.Empty(t, urls)
+ urls, err := LoadRegistries([]string{"bad"}, registries,
common.CONSUMER)
+ assert.Nil(t, urls)
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), `registry id "bad" url is invalid`)
+}
+
+func TestLoadRegistries_MissingRegistryID(t *testing.T) {
+ registries := map[string]*global.RegistryConfig{
+ "r1": {
+ Protocol: "mock",
+ Timeout: "2s",
+ Address: "127.0.0.1:2181",
+ },
+ }
+
+ urls, err := LoadRegistries([]string{"missing"}, registries,
common.CONSUMER)
+ assert.Nil(t, urls)
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), `registry id "missing" not found`)
}
func TestToURLs_EmptyOrNA(t *testing.T) {
@@ -254,3 +273,34 @@ func TestClientNameID(t *testing.T) {
got := clientNameID("nacos", "127.0.0.1:8848")
assert.Equal(t, "dubbo.registries-nacos-127.0.0.1:8848", got)
}
+
+func TestValidateMethodConfig(t *testing.T) {
+ t.Run("valid method config", func(t *testing.T) {
+ method := &global.MethodConfig{
+ Name: "testMethod",
+ TpsLimitRate: "1",
+ TpsLimitInterval: "10",
+ }
+ require.NoError(t, ValidateMethodConfig(method))
+ })
+
+ t.Run("negative tps rate", func(t *testing.T) {
+ method := &global.MethodConfig{
+ Name: "testMethod",
+ TpsLimitRate: "-1",
+ }
+ err := ValidateMethodConfig(method)
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "tps.limit.rate")
+ })
+
+ t.Run("invalid tps interval", func(t *testing.T) {
+ method := &global.MethodConfig{
+ Name: "testMethod",
+ TpsLimitInterval: "bad",
+ }
+ err := ValidateMethodConfig(method)
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "tps.limit.interval")
+ })
+}
diff --git a/server/action.go b/server/action.go
index a90136b20..e7d593157 100644
--- a/server/action.go
+++ b/server/action.go
@@ -141,7 +141,11 @@ func (svcOpts *ServiceOptions) Export() error {
regUrls := make([]*common.URL, 0)
if !svcConf.NotRegister {
- regUrls = internal.LoadRegistries(svcConf.RegistryIDs,
svcOpts.Registries, common.PROVIDER)
+ var err error
+ regUrls, err = internal.LoadRegistries(svcConf.RegistryIDs,
svcOpts.Registries, common.PROVIDER)
+ if err != nil {
+ return err
+ }
}
urlMap := svcOpts.getUrlMap()
diff --git a/server/action_test.go b/server/action_test.go
index dcb0331bb..f4a5c0af8 100644
--- a/server/action_test.go
+++ b/server/action_test.go
@@ -23,6 +23,7 @@ import (
import (
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
"go.uber.org/atomic"
)
@@ -499,6 +500,26 @@ func TestSetRegistrySubURL(t *testing.T) {
assert.NotNil(t, regURL.SubURL)
}
+func TestExportReturnsRegistryLoadError(t *testing.T) {
+ svcOpts := &ServiceOptions{
+ Service: &global.ServiceConfig{
+ Interface: "com.example.Service",
+ RegistryIDs: []string{"bad"},
+ NotRegister: false,
+ },
+ Registries: map[string]*global.RegistryConfig{
+ "bad": {
+ Protocol: "mock",
+ Address: "127.0.0.1:bad",
+ },
+ },
+ }
+
+ err := svcOpts.Export()
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), `registry id "bad" url is invalid`)
+}
+
// Test Unexport when exported
func TestUnexportWhenExported(t *testing.T) {
svcOpts := &ServiceOptions{
diff --git a/server/options.go b/server/options.go
index fb064a46d..62013bf8f 100644
--- a/server/options.go
+++ b/server/options.go
@@ -18,6 +18,7 @@
package server
import (
+ "fmt"
"reflect"
"strconv"
"sync"
@@ -42,6 +43,7 @@ import (
aslimiter "dubbo.apache.org/dubbo-go/v3/filter/adaptivesvc/limiter"
"dubbo.apache.org/dubbo-go/v3/global"
"dubbo.apache.org/dubbo-go/v3/graceful_shutdown"
+ "dubbo.apache.org/dubbo-go/v3/internal"
"dubbo.apache.org/dubbo-go/v3/metrics/probe"
"dubbo.apache.org/dubbo-go/v3/protocol"
"dubbo.apache.org/dubbo-go/v3/protocol/base"
@@ -87,6 +89,9 @@ func (srvOpts *ServerOptions) init(opts ...ServerOption)
error {
if len(providerConf.RegistryIDs) <= 0 {
providerConf.RegistryIDs = getRegistryIds(srvOpts.Registries)
}
+ if err := validateRegistryIDs(providerConf.RegistryIDs,
srvOpts.Registries); err != nil {
+ return err
+ }
providerConf.ProtocolIDs =
commonCfg.TranslateIds(providerConf.ProtocolIDs)
@@ -558,6 +563,8 @@ func (svcOpts *ServiceOptions) init(srv *Server, opts
...ServiceOption) error {
}
if len(svc.RegistryIDs) <= 0 {
svc.NotRegister = true
+ } else if err := validateRegistryIDs(svc.RegistryIDs,
svc.RCRegistriesMap); err != nil {
+ return err
}
svc.ProtocolIDs = commonCfg.TranslateIds(svc.ProtocolIDs)
@@ -573,6 +580,11 @@ func (svcOpts *ServiceOptions) init(srv *Server, opts
...ServiceOption) error {
if svc.TracingKey == "" {
svc.TracingKey = svcOpts.Provider.TracingKey
}
+ for _, method := range svc.Methods {
+ if err := internal.ValidateMethodConfig(method); err != nil {
+ return err
+ }
+ }
err := svcOpts.check()
if err != nil {
@@ -623,6 +635,15 @@ func WithFilter(filter string) ServiceOption {
}
}
+func validateRegistryIDs(ids []string, regs map[string]*global.RegistryConfig)
error {
+ for _, id := range ids {
+ if _, ok := regs[id]; !ok {
+ return fmt.Errorf("registry id %q not found", id)
+ }
+ }
+ return nil
+}
+
// todo(DMwangnima): think about a more ideal configuration style
func WithProtocolIDs(protocolIDs []string) ServiceOption {
return func(cfg *ServiceOptions) {
@@ -871,6 +892,18 @@ func WithRegistry(opts ...registry.Option) ServiceOption {
}
}
+func WithMethod(method *global.MethodConfig) ServiceOption {
+ return func(opts *ServiceOptions) {
+ if method == nil {
+ return
+ }
+ if opts.Service.Methods == nil {
+ opts.Service.Methods = make([]*global.MethodConfig, 0)
+ }
+ opts.Service.Methods = append(opts.Service.Methods, method)
+ }
+}
+
func WithParam(k, v string) ServiceOption {
return func(opts *ServiceOptions) {
if opts.Service.Params == nil {
diff --git a/server/options_test.go b/server/options_test.go
index 21d440653..97408d39f 100644
--- a/server/options_test.go
+++ b/server/options_test.go
@@ -63,6 +63,73 @@ func TestServerOptionsInitWithOptions(t *testing.T) {
assert.Equal(t, "test-group", opts.Provider.Group)
}
+func TestServerOptionsInitFailsOnMissingRegistryID(t *testing.T) {
+ opts := defaultServerOptions()
+ opts.Provider.RegistryIDs = []string{"missing"}
+ opts.Registries = map[string]*global.RegistryConfig{
+ "r1": {Protocol: "mock", Address: "127.0.0.1:2181"},
+ }
+
+ err := opts.init()
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), `registry id "missing" not found`)
+}
+
+func TestServiceOptionsInitFailsOnMissingRegistryID(t *testing.T) {
+ srv := &Server{
+ cfg: &ServerOptions{
+ Provider: &global.ProviderConfig{
+ ProtocolIDs: []string{"triple"},
+ },
+ Registries: map[string]*global.RegistryConfig{
+ "r1": {Protocol: "mock", Address:
"127.0.0.1:2181"},
+ },
+ Protocols: map[string]*global.ProtocolConfig{
+ "triple": {Name: "triple"},
+ },
+ Application: global.DefaultApplicationConfig(),
+ },
+ }
+ svcOpts := defaultServiceOptions()
+ svcOpts.Registries = srv.cfg.Registries
+ svcOpts.Protocols = srv.cfg.Protocols
+ svcOpts.Provider = srv.cfg.Provider
+
+ err := svcOpts.init(srv, func(opts *ServiceOptions) {
+ opts.Service.RegistryIDs = []string{"missing"}
+ })
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), `registry id "missing" not found`)
+}
+
+func TestServiceOptionsInitFailsOnInvalidMethodConfig(t *testing.T) {
+ srv := &Server{
+ cfg: &ServerOptions{
+ Provider: &global.ProviderConfig{
+ ProtocolIDs: []string{"triple"},
+ },
+ Protocols: map[string]*global.ProtocolConfig{
+ "triple": {Name: "triple"},
+ },
+ Application: global.DefaultApplicationConfig(),
+ },
+ }
+ svcOpts := defaultServiceOptions()
+ svcOpts.Protocols = srv.cfg.Protocols
+ svcOpts.Provider = srv.cfg.Provider
+
+ err := svcOpts.init(srv, func(opts *ServiceOptions) {
+ opts.Service.Methods = []*global.MethodConfig{
+ {
+ Name: "testMethod",
+ TpsLimitRate: "-1",
+ },
+ }
+ })
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "tps.limit.rate")
+}
+
// Test WithServerLoadBalanceConsistentHashing
func TestWithServerLoadBalanceConsistentHashing(t *testing.T) {
opts := defaultServerOptions()
@@ -805,6 +872,20 @@ func TestWithParam(t *testing.T) {
assert.Equal(t, "value1", opts.Service.Params["key1"])
}
+func TestWithMethod(t *testing.T) {
+ opts := defaultServiceOptions()
+ method := &global.MethodConfig{
+ Name: "testMethod",
+ Retries: "3",
+ }
+
+ opt := WithMethod(method)
+ opt(opts)
+
+ require.Len(t, opts.Service.Methods, 1)
+ assert.Equal(t, method, opts.Service.Methods[0])
+}
+
// Test WithParam creates params map if nil
func TestWithParamCreateMap(t *testing.T) {
opts := defaultServiceOptions()