blob: 1e8d213c1203c45911441aef0873bcf71dddbb5d [file]
/*
* 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 nacos
import (
"net/url"
"reflect"
"testing"
)
import (
nacosClient "github.com/dubbogo/gost/database/kv/nacos"
nacosConstant "github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"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"
)
func getRegURL() *common.URL {
regURLMap := url.Values{}
regURLMap.Set(constant.NacosNotLoadLocalCache, "true")
regURLMap.Set(constant.NacosNamespaceID, "nacos")
regURLMap.Set(constant.TimeoutKey, "5s")
regURLMap.Set(constant.ClientNameKey, "nacos-client")
regURL, _ := common.NewURL("registry://test.nacos.io:80", common.WithParams(regURLMap))
return regURL
}
type args struct {
url *common.URL
}
func TestNewNacosClientByURL(t *testing.T) {
oldNewNacosNamingClient := newNacosNamingClient
newNacosNamingClient = func(name string, share bool, sc []nacosConstant.ServerConfig,
cc nacosConstant.ClientConfig) (*nacosClient.NacosNamingClient, error) {
return &nacosClient.NacosNamingClient{}, nil
}
t.Cleanup(func() {
newNacosNamingClient = oldNewNacosNamingClient
})
tests := []struct {
name string
args args
want *nacosClient.NacosNamingClient
wantErr bool
}{
{
name: "test",
args: args{
url: getRegURL(),
},
want: &nacosClient.NacosNamingClient{},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := NewNacosClientByURL(tt.args.url)
if (err != nil) != tt.wantErr {
t.Errorf("NewNacosClientByURL() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewNacosClientByURL() got = %v, want %v", got, tt.want)
}
})
}
}
func TestNewNacosClientByURLMissingClientName(t *testing.T) {
regURLMap := url.Values{}
regURLMap.Set(constant.NacosNamespaceID, "nacos")
regURL, _ := common.NewURL("registry://test.nacos.io:80", common.WithParams(regURLMap))
client, err := NewNacosClientByURL(regURL)
assert.Nil(t, client)
assert.Error(t, err)
}
func TestGetNacosConfig(t *testing.T) {
tests := []struct {
name string
args args
want []nacosConstant.ServerConfig
want1 nacosConstant.ClientConfig
wantErr bool
}{
{
name: "test",
args: args{
url: getRegURL(),
},
want: []nacosConstant.ServerConfig{
{
IpAddr: "test.nacos.io",
Port: 80,
},
},
wantErr: false,
},
{
name: "with_context_path",
args: args{
url: func() *common.URL {
regURLMap := url.Values{}
regURLMap.Set(constant.ClientNameKey, "nacos-client")
regURL, _ := common.NewURL("registry://test.nacos.io:80/nacos", common.WithParams(regURLMap))
return regURL
}(),
},
want: []nacosConstant.ServerConfig{
{
IpAddr: "test.nacos.io",
Port: 80,
ContextPath: "/nacos",
},
},
wantErr: false,
},
{
name: "endpoint_only",
args: args{
url: func() *common.URL {
regURLMap := url.Values{}
regURLMap.Set(constant.NacosEndpoint, "acm.aliyun.com")
regURLMap.Set(constant.ClientNameKey, "nacos-client")
regURL, _ := common.NewURL("registry://test.nacos.io:80", common.WithParams(regURLMap))
return regURL
}(),
},
want: nil,
wantErr: false,
},
{
name: "nil_url",
args: args{
url: nil,
},
want: []nacosConstant.ServerConfig{},
wantErr: true,
},
{
name: "empty_location",
args: args{
url: func() *common.URL {
regURL, _ := common.NewURL("registry://", common.WithParams(url.Values{}))
return regURL
}(),
},
want: []nacosConstant.ServerConfig{},
wantErr: true,
},
{
name: "bad_address",
args: args{
url: func() *common.URL {
regURL, _ := common.NewURL("registry://bad-address", common.WithParams(url.Values{}))
return regURL
}(),
},
want: []nacosConstant.ServerConfig{},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got1, err := GetNacosConfig(tt.args.url)
if (err != nil) != tt.wantErr {
t.Errorf("GetNacosConfig() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("GetNacosConfig() got = %v, want %v", got, tt.want)
}
if !tt.wantErr {
assert.NotNil(t, got1)
}
})
}
}
func TestNewNacosConfigClientByUrl(t *testing.T) {
oldNewNacosConfigClient := newNacosConfigClient
newNacosConfigClient = func(name string, share bool, sc []nacosConstant.ServerConfig,
cc nacosConstant.ClientConfig) (*nacosClient.NacosConfigClient, error) {
return &nacosClient.NacosConfigClient{}, nil
}
t.Cleanup(func() {
newNacosConfigClient = oldNewNacosConfigClient
})
tests := []struct {
name string
args args
want *nacosClient.NacosConfigClient
wantErr bool
}{
{
name: "test",
args: args{
url: getRegURL(),
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := NewNacosConfigClientByUrl(tt.args.url)
if (err != nil) != tt.wantErr {
t.Errorf("NewNacosConfigClientByUrl() error = %v, wantErr %v", err, tt.wantErr)
return
}
assert.NotNil(t, got)
})
}
}
func TestNewNacosConfigClientByUrlMissingClientName(t *testing.T) {
regURLMap := url.Values{}
regURLMap.Set(constant.NacosNamespaceID, "nacos")
regURL, _ := common.NewURL("registry://test.nacos.io:80", common.WithParams(regURLMap))
client, err := NewNacosConfigClientByUrl(regURL)
assert.Nil(t, client)
assert.Error(t, err)
}
func TestNacosClientPoolKeySharedAcrossRoles(t *testing.T) {
var captured []string
oldNewNacosConfigClient := newNacosConfigClient
newNacosConfigClient = func(name string, share bool, sc []nacosConstant.ServerConfig,
cc nacosConstant.ClientConfig) (*nacosClient.NacosConfigClient, error) {
captured = append(captured, name)
assert.True(t, share)
return &nacosClient.NacosConfigClient{}, nil
}
t.Cleanup(func() {
newNacosConfigClient = oldNewNacosConfigClient
})
mkURL := func(clientName, namespace string) *common.URL {
m := url.Values{}
m.Set(constant.NacosNamespaceID, namespace)
m.Set(constant.ClientNameKey, clientName)
u, _ := common.NewURL("registry://test.nacos.io:80", common.WithParams(m))
return u
}
// config-center and metadata-report carry role-scoped client names, but
// point at the same cluster: they must resolve to one pool key (#3573).
_, err := NewNacosConfigClientByUrl(mkURL("dubbo.config-center-nacos-test.nacos.io:80", "ns1"))
require.NoError(t, err)
_, err = NewNacosConfigClientByUrl(mkURL("dubbo.metadata-report-nacos-test.nacos.io:80", "ns1"))
require.NoError(t, err)
assert.Equal(t, captured[0], captured[1])
// A different namespace is a different connection identity and must not
// share the client.
_, err = NewNacosConfigClientByUrl(mkURL("dubbo.config-center-nacos-test.nacos.io:80", "ns2"))
require.NoError(t, err)
assert.NotEqual(t, captured[0], captured[2])
}
func TestNacosClientPoolKeyCredentialAndEndpointIdentity(t *testing.T) {
// Clean up global credential IDs to avoid race conditions with other tests
credentialIDsMu.Lock()
oldCredentialIDs := credentialIDs
credentialIDs = make(map[string]string)
credentialIDsMu.Unlock()
t.Cleanup(func() {
credentialIDsMu.Lock()
credentialIDs = oldCredentialIDs
credentialIDsMu.Unlock()
})
key := func(params map[string]string) string {
m := url.Values{}
for k, v := range params {
m.Set(k, v)
}
u, _ := common.NewURL("registry://test.nacos.io:80", common.WithParams(m))
return nacosClientPoolKey("config", u)
}
userPass := map[string]string{constant.NacosUsername: "alice", constant.NacosPassword: "s3cret-A"}
// Same server and same full credential set share one key.
assert.Equal(t, key(userPass), key(map[string]string{constant.NacosUsername: "alice", constant.NacosPassword: "s3cret-A"}))
// A different password (or secretKey) is a differently authenticated
// client and must never collapse into the same pool entry.
assert.NotEqual(t, key(userPass), key(map[string]string{constant.NacosUsername: "alice", constant.NacosPassword: "s3cret-B"}))
assert.NotEqual(t,
key(map[string]string{constant.NacosAccessKey: "AKID", constant.NacosSecretKey: "SK-1"}),
key(map[string]string{constant.NacosAccessKey: "AKID", constant.NacosSecretKey: "SK-2"}))
// Credentials must not appear in the key verbatim (keys can be logged).
assert.NotContains(t, key(userPass), "alice")
assert.NotContains(t, key(userPass), "s3cret-A")
// When an endpoint is set, GetNacosConfig ignores url.Location; the pool
// key mirrors that, so differing (ignored) locations still share.
withEndpoint := func(location string) string {
m := url.Values{}
m.Set(constant.NacosEndpoint, "acm.aliyun.com")
u, _ := common.NewURL("registry://"+location, common.WithParams(m))
return nacosClientPoolKey("config", u)
}
assert.Equal(t, withEndpoint("a.nacos.io:80"), withEndpoint("b.nacos.io:80"))
}
func TestNacosNamingAndConfigPoolKeysDistinct(t *testing.T) {
var namingKey, configKey string
oldNaming := newNacosNamingClient
oldConfig := newNacosConfigClient
newNacosNamingClient = func(name string, share bool, sc []nacosConstant.ServerConfig,
cc nacosConstant.ClientConfig) (*nacosClient.NacosNamingClient, error) {
namingKey = name
return &nacosClient.NacosNamingClient{}, nil
}
newNacosConfigClient = func(name string, share bool, sc []nacosConstant.ServerConfig,
cc nacosConstant.ClientConfig) (*nacosClient.NacosConfigClient, error) {
configKey = name
return &nacosClient.NacosConfigClient{}, nil
}
t.Cleanup(func() {
newNacosNamingClient = oldNaming
newNacosConfigClient = oldConfig
})
regURL := getRegURL()
_, err := NewNacosClientByURL(regURL)
require.NoError(t, err)
_, err = NewNacosConfigClientByUrl(regURL)
require.NoError(t, err)
assert.NotEqual(t, namingKey, configKey)
}
func TestNacosClientPoolKeyDistinguishesByPath(t *testing.T) {
// Clean up global credential IDs to avoid race conditions with other tests
credentialIDsMu.Lock()
oldCredentialIDs := credentialIDs
credentialIDs = make(map[string]string)
credentialIDsMu.Unlock()
t.Cleanup(func() {
credentialIDsMu.Lock()
credentialIDs = oldCredentialIDs
credentialIDsMu.Unlock()
})
key := func(path string) string {
m := url.Values{}
m.Set(constant.ClientNameKey, "test-client")
m.Set(constant.NacosNamespaceID, "default")
u, _ := common.NewURL("registry://localhost:8848"+path, common.WithParams(m))
return nacosClientPoolKey("config", u)
}
// URLs with different paths must generate different pool keys (#3635)
keyNacos := key("/nacos")
keyCustom := key("/custom")
keyEmpty := key("")
assert.NotEqual(t, keyNacos, keyCustom, "different paths should create different pool keys")
assert.NotEqual(t, keyNacos, keyEmpty, "path /nacos should differ from empty path")
assert.NotEqual(t, keyCustom, keyEmpty, "path /custom should differ from empty path")
// Same path should generate same key
assert.Equal(t, keyNacos, key("/nacos"), "same path should create same pool key")
}