This is an automated email from the ASF dual-hosted git repository.
xuetaoli 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 58805d6cf fix: nil pointer bug (#3071)
58805d6cf is described below
commit 58805d6cfe5d0ad607708ed35e625a3959f493fb
Author: Xuetao Li <[email protected]>
AuthorDate: Sun Nov 16 20:31:58 2025 +0800
fix: nil pointer bug (#3071)
* fix: nil pointer bug
---
cluster/cluster/failover/cluster_invoker.go | 5 +-
cluster/cluster/failover/cluster_invoker_test.go | 176 +++++++++++++++++++++++
2 files changed, 179 insertions(+), 2 deletions(-)
diff --git a/cluster/cluster/failover/cluster_invoker.go
b/cluster/cluster/failover/cluster_invoker.go
index c1248a3d4..6b54d7290 100644
--- a/cluster/cluster/failover/cluster_invoker.go
+++ b/cluster/cluster/failover/cluster_invoker.go
@@ -85,9 +85,10 @@ func (invoker *failoverClusterInvoker) Invoke(ctx
context.Context, invocation pr
}
invoked = append(invoked, ivk)
// DO INVOKE
+ ivkURL := ivk.GetURL().Key()
res = ivk.Invoke(ctx, invocation)
if res.Error() != nil && !isBizError(res.Error()) {
- providers = append(providers, ivk.GetURL().Key())
+ providers = append(providers, ivkURL)
continue
}
return res
@@ -104,7 +105,7 @@ func (invoker *failoverClusterInvoker) Invoke(ctx
context.Context, invocation pr
}
logger.Errorf(fmt.Sprintf("Failed to invoke the method %v in the
service %v. "+
- "Tried %v times of the providers %v (%v/%v)from the registry %v
on the consumer %v using the dubbo version %v. "+
+ "Tried %v times of the providers %v (%v/%v) from the registry
%v on the consumer %v using the dubbo version %v. "+
"Last error is %+v.", methodName, invokerSvc, retries,
providers, len(providers), len(invokers),
invokerUrl, ip, constant.Version, res.Error().Error()))
diff --git a/cluster/cluster/failover/cluster_invoker_test.go
b/cluster/cluster/failover/cluster_invoker_test.go
new file mode 100644
index 000000000..35584cdd4
--- /dev/null
+++ b/cluster/cluster/failover/cluster_invoker_test.go
@@ -0,0 +1,176 @@
+/*
+ * 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 failover
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "testing"
+)
+
+import (
+ "github.com/golang/mock/gomock"
+
+ "github.com/stretchr/testify/assert"
+)
+
+import (
+ clusterpkg "dubbo.apache.org/dubbo-go/v3/cluster/cluster"
+ "dubbo.apache.org/dubbo-go/v3/cluster/directory/static"
+ "dubbo.apache.org/dubbo-go/v3/cluster/loadbalance/random"
+ "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/protocol/base"
+ "dubbo.apache.org/dubbo-go/v3/protocol/invocation"
+ "dubbo.apache.org/dubbo-go/v3/protocol/mock"
+ "dubbo.apache.org/dubbo-go/v3/protocol/result"
+)
+
+var broadcastUrl, _ = common.NewURL(
+ fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider",
constant.LocalHostValue, constant.DefaultPort))
+
+func registerFailover(mockInvokers ...*mock.MockInvoker) base.Invoker {
+ extension.SetLoadbalance("random", random.NewRandomLoadBalance)
+
+ invokers := []base.Invoker{}
+ for _, ivk := range mockInvokers {
+ invokers = append(invokers, ivk)
+ ivk.EXPECT().GetURL().Return(broadcastUrl).AnyTimes()
+ }
+ staticDir := static.NewDirectory(invokers)
+
+ cluster := newFailoverClusterInvoker(staticDir)
+ return cluster
+}
+
+func TestBroadcastInvokeSuccess(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ invokers := make([]*mock.MockInvoker, 0)
+
+ mockResult := &result.RPCResult{Rest: clusterpkg.Rest{Tried: 0,
Success: true}}
+ for i := 0; i < 3; i++ {
+ invoker := mock.NewMockInvoker(ctrl)
+ invokers = append(invokers, invoker)
+ invoker.EXPECT().Invoke(gomock.Any(),
gomock.Any()).Return(mockResult).AnyTimes()
+ invoker.EXPECT().IsAvailable().Return(true).AnyTimes() // Mock
IsAvailable to return true
+ }
+
+ clusterInvoker := registerFailover(invokers...)
+
+ result := clusterInvoker.Invoke(context.Background(),
&invocation.RPCInvocation{})
+ assert.Equal(t, mockResult, result)
+}
+
+func TestBroadcastInvokeFailedOver(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ invokers := make([]*mock.MockInvoker, 0)
+
+ mockResult := &result.RPCResult{Rest: clusterpkg.Rest{Tried: 0,
Success: true}}
+ mockFailedResult := &result.RPCResult{Err: errors.New("just failed")}
+
+ // Create 10 invokers that return a successful result
+ for i := 0; i < 10; i++ {
+ invoker := mock.NewMockInvoker(ctrl)
+ invokers = append(invokers, invoker)
+ invoker.EXPECT().IsAvailable().Return(true).AnyTimes() // Mock
IsAvailable to return true
+ invoker.EXPECT().Invoke(gomock.Any(),
gomock.Any()).Return(mockResult).AnyTimes()
+ }
+
+ // Create 1 invoker that returns a failed result
+ {
+ invoker := mock.NewMockInvoker(ctrl)
+ invokers = append(invokers, invoker)
+ invoker.EXPECT().IsAvailable().Return(false).AnyTimes() // Mock
IsAvailable to return true
+ invoker.EXPECT().Invoke(gomock.Any(),
gomock.Any()).Return(mockFailedResult).AnyTimes()
+ }
+
+ // Create 10 more invokers that return successful results
+ for i := 0; i < 10; i++ {
+ invoker := mock.NewMockInvoker(ctrl)
+ invokers = append(invokers, invoker)
+ invoker.EXPECT().IsAvailable().Return(true).AnyTimes() // Mock
IsAvailable to return true
+ invoker.EXPECT().Invoke(gomock.Any(),
gomock.Any()).Return(mockResult).AnyTimes()
+ }
+
+ // Register the clusterInvoker
+ clusterInvoker := registerFailover(invokers...)
+
+ // Perform the invocation
+ result := clusterInvoker.Invoke(context.Background(),
&invocation.RPCInvocation{})
+
+ // Assert that the result is the same as the failed result
+ assert.Equal(t, nil, result.Error())
+}
+
+func TestBroadcastInvokeFailed(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ invokers := make([]*mock.MockInvoker, 0)
+
+ mockFailedResult := &result.RPCResult{Err: errors.New("just failed")}
+
+ // Create 1 invoker that returns a failed result
+ {
+ invoker := mock.NewMockInvoker(ctrl)
+ invokers = append(invokers, invoker)
+ invoker.EXPECT().IsAvailable().Return(true).AnyTimes() // Mock
IsAvailable to return true
+ invoker.EXPECT().Invoke(gomock.Any(),
gomock.Any()).Return(mockFailedResult).AnyTimes()
+ }
+
+ // Register the clusterInvoker
+ clusterInvoker := registerFailover(invokers...)
+
+ // Perform the invocation
+ result := clusterInvoker.Invoke(context.Background(),
&invocation.RPCInvocation{})
+
+ // Assert that the result is the same as the failed result
+ assert.Equal(t, mockFailedResult.Err, result.Error())
+}
+
+func TestBroadcastInvokeFailedNoServer(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ invokers := make([]*mock.MockInvoker, 0)
+
+ mockFailedResult := &result.RPCResult{Err: errors.New("just failed")}
+
+ // Create 1 invoker that returns a failed result
+ {
+ invoker := mock.NewMockInvoker(ctrl)
+ invokers = append(invokers, invoker)
+ invoker.EXPECT().IsAvailable().Return(false).AnyTimes() // Mock
IsAvailable to return true
+ invoker.EXPECT().Invoke(gomock.Any(),
gomock.Any()).Return(mockFailedResult).AnyTimes()
+ }
+
+ // Register the clusterInvoker
+ clusterInvoker := registerFailover(invokers...)
+
+ // Perform the invocation
+ result := clusterInvoker.Invoke(context.Background(),
&invocation.RPCInvocation{})
+
+ // Assert that the result is the same as the failed result
+ assert.Equal(t, "Failed to invoke the method of the service
com.ikurento.user.UserProvider .No provider is available because can't connect
server.", result.Error().Error())
+}