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 992c2972c test: add unit test for protocol/base (#3139)
992c2972c is described below
commit 992c2972cb573aae5bf7ed91fb397ca2fc13fe38
Author: Akashisang <[email protected]>
AuthorDate: Sat Dec 27 16:00:48 2025 +0800
test: add unit test for protocol/base (#3139)
* test: add unit test for protocol/base
---
protocol/base/base_exporter_test.go | 113 ++++++++++++++++
protocol/base/base_invoker_test.go | 104 +++++++++++++++
protocol/base/base_protocol_test.go | 250 ++++++++++++++++++++++++++++++++++++
protocol/base/rpc_status_test.go | 183 +++++++++++++++++++++++++-
4 files changed, 649 insertions(+), 1 deletion(-)
diff --git a/protocol/base/base_exporter_test.go
b/protocol/base/base_exporter_test.go
new file mode 100644
index 000000000..e7f14e64d
--- /dev/null
+++ b/protocol/base/base_exporter_test.go
@@ -0,0 +1,113 @@
+/*
+ * 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 base
+
+import (
+ "sync"
+ "testing"
+)
+
+import (
+ "github.com/stretchr/testify/assert"
+)
+
+import (
+ "dubbo.apache.org/dubbo-go/v3/common"
+)
+
+func TestNewBaseExporter(t *testing.T) {
+ url, _ := common.NewURL("dubbo://localhost:9090")
+ invoker := NewBaseInvoker(url)
+ exporterMap := &sync.Map{}
+ key := "test-key"
+
+ exporter := NewBaseExporter(key, invoker, exporterMap)
+
+ assert.NotNil(t, exporter)
+ assert.Equal(t, key, exporter.key)
+ assert.Equal(t, invoker, exporter.invoker)
+ assert.Equal(t, exporterMap, exporter.exporterMap)
+}
+
+func TestBaseExporter_GetInvoker(t *testing.T) {
+ url, _ := common.NewURL("dubbo://localhost:9090")
+ invoker := NewBaseInvoker(url)
+ exporterMap := &sync.Map{}
+ key := "test-key"
+
+ exporter := NewBaseExporter(key, invoker, exporterMap)
+ gotInvoker := exporter.GetInvoker()
+
+ assert.NotNil(t, gotInvoker)
+ assert.Equal(t, invoker, gotInvoker)
+ assert.Equal(t, url, gotInvoker.GetURL())
+}
+
+func TestBaseExporter_UnExport(t *testing.T) {
+ url, _ := common.NewURL("dubbo://localhost:9090")
+ invoker := NewBaseInvoker(url)
+ exporterMap := &sync.Map{}
+ key := "test-key"
+
+ // Store the exporter in the map
+ exporter := NewBaseExporter(key, invoker, exporterMap)
+ exporterMap.Store(key, exporter)
+
+ // Verify it's stored
+ _, ok := exporterMap.Load(key)
+ assert.True(t, ok)
+
+ // Test UnExport
+ exporter.UnExport()
+
+ // Verify invoker is destroyed
+ assert.True(t, invoker.IsDestroyed())
+ assert.False(t, invoker.IsAvailable())
+
+ // Verify exporter is removed from map
+ _, ok = exporterMap.Load(key)
+ assert.False(t, ok)
+}
+
+func TestBaseExporter_UnExport_MultipleEntries(t *testing.T) {
+ exporterMap := &sync.Map{}
+
+ // Create multiple exporters
+ url1, _ := common.NewURL("dubbo://localhost:9090")
+ invoker1 := NewBaseInvoker(url1)
+ exporter1 := NewBaseExporter("key1", invoker1, exporterMap)
+ exporterMap.Store("key1", exporter1)
+
+ url2, _ := common.NewURL("dubbo://localhost:9091")
+ invoker2 := NewBaseInvoker(url2)
+ exporter2 := NewBaseExporter("key2", invoker2, exporterMap)
+ exporterMap.Store("key2", exporter2)
+
+ // Unexport first exporter
+ exporter1.UnExport()
+
+ // Verify first is removed, second remains
+ _, ok1 := exporterMap.Load("key1")
+ assert.False(t, ok1)
+ _, ok2 := exporterMap.Load("key2")
+ assert.True(t, ok2)
+
+ // Verify only first invoker is destroyed
+ assert.True(t, invoker1.IsDestroyed())
+ assert.False(t, invoker2.IsDestroyed())
+}
diff --git a/protocol/base/base_invoker_test.go
b/protocol/base/base_invoker_test.go
index badba1ca9..7182a49cf 100644
--- a/protocol/base/base_invoker_test.go
+++ b/protocol/base/base_invoker_test.go
@@ -18,6 +18,7 @@
package base
import (
+ "context"
"testing"
)
@@ -42,3 +43,106 @@ func TestBaseInvoker(t *testing.T) {
assert.False(t, ivk.IsAvailable())
assert.True(t, ivk.IsDestroyed())
}
+
+func TestBaseInvokerWithFullURL(t *testing.T) {
+ url, err :=
common.NewURL("dubbo://localhost:20880/com.example.Service?version=1.0.0&group=test")
+ assert.Nil(t, err)
+
+ ivk := NewBaseInvoker(url)
+
+ // Test GetURL
+ returnedURL := ivk.GetURL()
+ assert.NotNil(t, returnedURL)
+ assert.Equal(t, "dubbo", returnedURL.Protocol)
+ assert.Equal(t, "localhost", returnedURL.Ip)
+ assert.Equal(t, "20880", returnedURL.Port)
+
+ // Test initial state
+ assert.True(t, ivk.IsAvailable())
+ assert.False(t, ivk.IsDestroyed())
+
+ // Test String method before destroy
+ str := ivk.String()
+ assert.Contains(t, str, "dubbo")
+ assert.Contains(t, str, "localhost")
+ assert.Contains(t, str, "20880")
+
+ // Test Destroy
+ ivk.Destroy()
+ assert.False(t, ivk.IsAvailable())
+ assert.True(t, ivk.IsDestroyed())
+ assert.Nil(t, ivk.GetURL())
+
+ // Test String method after destroy (url is nil)
+ str = ivk.String()
+ assert.Contains(t, str, "BaseInvoker")
+}
+
+func TestBaseInvokerInvoke(t *testing.T) {
+ url, err := common.NewURL("dubbo://localhost:9090/test.Service")
+ assert.Nil(t, err)
+
+ ivk := NewBaseInvoker(url)
+
+ // Create a mock invocation
+ ctx := context.Background()
+
+ // Invoke method should return an empty RPCResult
+ result := ivk.Invoke(ctx, nil)
+ assert.NotNil(t, result)
+}
+
+func TestBaseInvokerMultipleDestroy(t *testing.T) {
+ url, err := common.NewURL("dubbo://localhost:9090")
+ assert.Nil(t, err)
+
+ ivk := NewBaseInvoker(url)
+
+ // First destroy
+ ivk.Destroy()
+ assert.True(t, ivk.IsDestroyed())
+ assert.False(t, ivk.IsAvailable())
+
+ // Second destroy should not cause panic
+ ivk.Destroy()
+ assert.True(t, ivk.IsDestroyed())
+ assert.False(t, ivk.IsAvailable())
+}
+
+func TestBaseInvokerStringWithDifferentURLs(t *testing.T) {
+ tests := []struct {
+ name string
+ urlStr string
+ contains []string
+ }{
+ {
+ name: "Standard URL",
+ urlStr: "dubbo://localhost:8080/test.Service",
+ contains: []string{"dubbo", "localhost", "8080",
"test.Service"},
+ },
+ {
+ name: "URL with path",
+ urlStr: "tri://localhost:9090/org.apache.Service",
+ contains: []string{"tri", "localhost", "9090",
"org.apache.Service"},
+ },
+ {
+ name: "URL with port only",
+ urlStr: "dubbo://:8888/Service",
+ contains: []string{"dubbo", "8888"},
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ url, err := common.NewURL(tt.urlStr)
+ assert.Nil(t, err)
+
+ ivk := NewBaseInvoker(url)
+ str := ivk.String()
+
+ for _, contain := range tt.contains {
+ assert.Contains(t, str, contain)
+ }
+ })
+ }
+}
diff --git a/protocol/base/base_protocol_test.go
b/protocol/base/base_protocol_test.go
new file mode 100644
index 000000000..2c35820e3
--- /dev/null
+++ b/protocol/base/base_protocol_test.go
@@ -0,0 +1,250 @@
+/*
+ * 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 base
+
+import (
+ "testing"
+)
+
+import (
+ "github.com/stretchr/testify/assert"
+)
+
+import (
+ "dubbo.apache.org/dubbo-go/v3/common"
+)
+
+func TestNewBaseProtocol(t *testing.T) {
+ protocol := NewBaseProtocol()
+
+ assert.NotNil(t, protocol)
+ assert.NotNil(t, protocol.exporterMap)
+ assert.Empty(t, protocol.invokers)
+}
+
+func TestBaseProtocol_SetExporterMap(t *testing.T) {
+ protocol := NewBaseProtocol()
+ url, _ := common.NewURL("dubbo://localhost:9090")
+ invoker := NewBaseInvoker(url)
+ exporter := NewBaseExporter("test-key", invoker, protocol.exporterMap)
+
+ protocol.SetExporterMap("test-key", exporter)
+
+ // Verify exporter is stored
+ val, ok := protocol.exporterMap.Load("test-key")
+ assert.True(t, ok)
+ assert.Equal(t, exporter, val)
+}
+
+func TestBaseProtocol_ExporterMap(t *testing.T) {
+ protocol := NewBaseProtocol()
+ exporterMap := protocol.ExporterMap()
+
+ assert.NotNil(t, exporterMap)
+ assert.Equal(t, protocol.exporterMap, exporterMap)
+}
+
+func TestBaseProtocol_SetInvokers(t *testing.T) {
+ protocol := NewBaseProtocol()
+ url1, _ := common.NewURL("dubbo://localhost:9090")
+ invoker1 := NewBaseInvoker(url1)
+ url2, _ := common.NewURL("dubbo://localhost:9091")
+ invoker2 := NewBaseInvoker(url2)
+
+ protocol.SetInvokers(invoker1)
+ protocol.SetInvokers(invoker2)
+
+ invokers := protocol.Invokers()
+ assert.Len(t, invokers, 2)
+ assert.Contains(t, invokers, invoker1)
+ assert.Contains(t, invokers, invoker2)
+}
+
+func TestBaseProtocol_Invokers(t *testing.T) {
+ protocol := NewBaseProtocol()
+ url, _ := common.NewURL("dubbo://localhost:9090")
+ invoker := NewBaseInvoker(url)
+
+ protocol.SetInvokers(invoker)
+ invokers := protocol.Invokers()
+
+ assert.Len(t, invokers, 1)
+ assert.Equal(t, invoker, invokers[0])
+}
+
+func TestBaseProtocol_Export(t *testing.T) {
+ protocol := NewBaseProtocol()
+ url, _ := common.NewURL("dubbo://localhost:9090")
+ invoker := NewBaseInvoker(url)
+
+ exporter := protocol.Export(invoker)
+
+ assert.NotNil(t, exporter)
+ assert.Equal(t, invoker, exporter.GetInvoker())
+
+ // Note: Export creates a BaseExporter but doesn't automatically store
it
+ // The exporter needs to be manually stored using SetExporterMap if
needed
+ baseExporter, ok := exporter.(*BaseExporter)
+ assert.True(t, ok)
+ assert.Equal(t, "base", baseExporter.key)
+ assert.Equal(t, protocol.exporterMap, baseExporter.exporterMap)
+}
+
+func TestBaseProtocol_Refer(t *testing.T) {
+ protocol := NewBaseProtocol()
+ url, _ := common.NewURL("dubbo://localhost:9090")
+
+ invoker := protocol.Refer(url)
+
+ assert.NotNil(t, invoker)
+ assert.Equal(t, url, invoker.GetURL())
+
+ // Type assert to BaseInvoker to access IsAvailable and IsDestroyed
+ baseInvoker, ok := invoker.(*BaseInvoker)
+ assert.True(t, ok)
+ assert.True(t, baseInvoker.IsAvailable())
+ assert.False(t, baseInvoker.IsDestroyed())
+}
+
+func TestBaseProtocol_Destroy(t *testing.T) {
+ protocol := NewBaseProtocol()
+
+ // Add invokers
+ url1, _ := common.NewURL("dubbo://localhost:9090")
+ invoker1 := NewBaseInvoker(url1)
+ protocol.SetInvokers(invoker1)
+
+ url2, _ := common.NewURL("dubbo://localhost:9091")
+ invoker2 := NewBaseInvoker(url2)
+ protocol.SetInvokers(invoker2)
+
+ // Add exporters
+ exporter1 := NewBaseExporter("key1", invoker1, protocol.exporterMap)
+ protocol.SetExporterMap("key1", exporter1)
+
+ exporter2 := NewBaseExporter("key2", invoker2, protocol.exporterMap)
+ protocol.SetExporterMap("key2", exporter2)
+
+ // Verify setup
+ assert.Len(t, protocol.Invokers(), 2)
+ _, ok1 := protocol.exporterMap.Load("key1")
+ assert.True(t, ok1)
+ _, ok2 := protocol.exporterMap.Load("key2")
+ assert.True(t, ok2)
+
+ // Test Destroy
+ protocol.Destroy()
+
+ // Verify all invokers are destroyed
+ assert.Empty(t, protocol.Invokers())
+ assert.True(t, invoker1.IsDestroyed())
+ assert.True(t, invoker2.IsDestroyed())
+
+ // Verify all exporters are unexported and removed
+ _, ok1 = protocol.exporterMap.Load("key1")
+ assert.False(t, ok1)
+ _, ok2 = protocol.exporterMap.Load("key2")
+ assert.False(t, ok2)
+}
+
+func TestBaseProtocol_Destroy_WithNilInvoker(t *testing.T) {
+ protocol := NewBaseProtocol()
+
+ // Add a nil invoker
+ protocol.invokers = append(protocol.invokers, nil)
+
+ // Add a valid invoker
+ url, _ := common.NewURL("dubbo://localhost:9090")
+ invoker := NewBaseInvoker(url)
+ protocol.SetInvokers(invoker)
+
+ // Should not panic
+ assert.NotPanics(t, func() {
+ protocol.Destroy()
+ })
+
+ assert.Empty(t, protocol.Invokers())
+}
+
+func TestBaseProtocol_Destroy_WithNilExporter(t *testing.T) {
+ protocol := NewBaseProtocol()
+
+ // Add a nil exporter
+ protocol.exporterMap.Store("nil-key", nil)
+
+ // Add a valid exporter
+ url, _ := common.NewURL("dubbo://localhost:9090")
+ invoker := NewBaseInvoker(url)
+ exporter := NewBaseExporter("valid-key", invoker, protocol.exporterMap)
+ protocol.SetExporterMap("valid-key", exporter)
+
+ // Should not panic
+ assert.NotPanics(t, func() {
+ protocol.Destroy()
+ })
+
+ // Verify nil entry is deleted
+ _, ok := protocol.exporterMap.Load("nil-key")
+ assert.False(t, ok)
+
+ // Verify valid exporter is unexported
+ _, ok = protocol.exporterMap.Load("valid-key")
+ assert.False(t, ok)
+}
+
+func TestBaseProtocol_Destroy_EmptyProtocol(t *testing.T) {
+ protocol := NewBaseProtocol()
+
+ // Should not panic on empty protocol
+ assert.NotPanics(t, func() {
+ protocol.Destroy()
+ })
+
+ assert.Empty(t, protocol.Invokers())
+}
+
+func TestBaseProtocol_MultipleExportRefer(t *testing.T) {
+ protocol := NewBaseProtocol()
+
+ // Export multiple services
+ url1, _ := common.NewURL("dubbo://localhost:9090/service1")
+ invoker1 := NewBaseInvoker(url1)
+ exporter1 := protocol.Export(invoker1)
+
+ url2, _ := common.NewURL("dubbo://localhost:9091/service2")
+ invoker2 := NewBaseInvoker(url2)
+ exporter2 := protocol.Export(invoker2)
+
+ // Refer multiple services
+ url3, _ := common.NewURL("dubbo://localhost:9092/service3")
+ referInvoker1 := protocol.Refer(url3)
+
+ url4, _ := common.NewURL("dubbo://localhost:9093/service4")
+ referInvoker2 := protocol.Refer(url4)
+
+ // Verify all are created correctly
+ assert.NotNil(t, exporter1)
+ assert.NotNil(t, exporter2)
+ assert.NotNil(t, referInvoker1)
+ assert.NotNil(t, referInvoker2)
+
+ assert.Equal(t, url1, exporter1.GetInvoker().GetURL())
+ assert.Equal(t, url2, exporter2.GetInvoker().GetURL())
+ assert.Equal(t, url3, referInvoker1.GetURL())
+ assert.Equal(t, url4, referInvoker2.GetURL())
+}
diff --git a/protocol/base/rpc_status_test.go b/protocol/base/rpc_status_test.go
index 277634732..07b6e89e1 100644
--- a/protocol/base/rpc_status_test.go
+++ b/protocol/base/rpc_status_test.go
@@ -31,7 +31,7 @@ import (
)
const (
- mockCommonDubboUrl =
"dubbo://192.168.10.10:20000/com.ikurento.user.UserProvider" //NOSONAR just for
test
+ mockCommonDubboUrl =
"dubbo://localhost:20000/com.ikurento.user.UserProvider"
)
func TestBeginCount(t *testing.T) {
@@ -155,3 +155,184 @@ func TestCurrentTimeMillis(t *testing.T) {
i, _ := strconv.ParseInt(str, 10, 64)
assert.Equal(t, c, i)
}
+
+func TestRPCStatusGetters(t *testing.T) {
+ defer CleanAllStatus()
+
+ url, _ := common.NewURL(mockCommonDubboUrl)
+
+ // Test all getter methods
+ request(url, "test", 100, false, true)
+
+ urlStatus := GetURLStatus(url)
+ methodStatus := GetMethodStatus(url, "test")
+
+ // Test GetActive
+ assert.Equal(t, int32(0), urlStatus.GetActive())
+ assert.Equal(t, int32(0), methodStatus.GetActive())
+
+ // Test GetTotal
+ assert.Equal(t, int32(1), urlStatus.GetTotal())
+ assert.Equal(t, int32(1), methodStatus.GetTotal())
+
+ // Test GetFailed
+ assert.Equal(t, int32(0), urlStatus.GetFailed())
+ assert.Equal(t, int32(0), methodStatus.GetFailed())
+
+ // Test GetTotalElapsed
+ assert.Equal(t, int64(100), urlStatus.GetTotalElapsed())
+ assert.Equal(t, int64(100), methodStatus.GetTotalElapsed())
+
+ // Test GetFailedElapsed
+ assert.Equal(t, int64(0), urlStatus.GetFailedElapsed())
+ assert.Equal(t, int64(0), methodStatus.GetFailedElapsed())
+
+ // Test GetMaxElapsed
+ assert.Equal(t, int64(100), urlStatus.GetMaxElapsed())
+ assert.Equal(t, int64(100), methodStatus.GetMaxElapsed())
+
+ // Test GetFailedMaxElapsed
+ assert.Equal(t, int64(0), urlStatus.GetFailedMaxElapsed())
+ assert.Equal(t, int64(0), methodStatus.GetFailedMaxElapsed())
+
+ // Test GetSucceededMaxElapsed
+ assert.Equal(t, int64(100), urlStatus.GetSucceededMaxElapsed())
+ assert.Equal(t, int64(100), methodStatus.GetSucceededMaxElapsed())
+
+ // Test GetSuccessiveRequestFailureCount
+ assert.Equal(t, int32(0), urlStatus.GetSuccessiveRequestFailureCount())
+ assert.Equal(t, int32(0),
methodStatus.GetSuccessiveRequestFailureCount())
+
+ // Add a failed request to test failure-related getters
+ request(url, "test", 150, false, false)
+
+ assert.Equal(t, int32(1), urlStatus.GetFailed())
+ assert.Equal(t, int64(150), urlStatus.GetFailedElapsed())
+ assert.Equal(t, int64(150), urlStatus.GetFailedMaxElapsed())
+ assert.Equal(t, int32(1), urlStatus.GetSuccessiveRequestFailureCount())
+
+ // Test GetLastRequestFailedTimestamp
+ timestamp := urlStatus.GetLastRequestFailedTimestamp()
+ assert.True(t, timestamp > 0)
+}
+
+func TestInvokerBlackList(t *testing.T) {
+ defer CleanAllStatus()
+
+ url, _ := common.NewURL(mockCommonDubboUrl)
+ invoker := NewBaseInvoker(url)
+
+ // Test healthy status initially
+ assert.True(t, GetInvokerHealthyStatus(invoker))
+
+ // Set invoker to unhealthy
+ SetInvokerUnhealthyStatus(invoker)
+ assert.False(t, GetInvokerHealthyStatus(invoker))
+
+ // Test GetBlackListInvokers
+ blackListInvokers := GetBlackListInvokers(10)
+ assert.Equal(t, 1, len(blackListInvokers))
+ assert.Equal(t, invoker.GetURL().Key(),
blackListInvokers[0].GetURL().Key())
+
+ // Test with blockSize smaller than actual size
+ blackListInvokers = GetBlackListInvokers(0)
+ assert.Equal(t, 0, len(blackListInvokers))
+
+ // Remove invoker from unhealthy status
+ RemoveInvokerUnhealthyStatus(invoker)
+ assert.True(t, GetInvokerHealthyStatus(invoker))
+
+ // Test RemoveUrlKeyUnhealthyStatus
+ SetInvokerUnhealthyStatus(invoker)
+ assert.False(t, GetInvokerHealthyStatus(invoker))
+ RemoveUrlKeyUnhealthyStatus(invoker.GetURL().Key())
+ assert.True(t, GetInvokerHealthyStatus(invoker))
+}
+
+func TestGetAndRefreshState(t *testing.T) {
+ defer CleanAllStatus()
+
+ url, _ := common.NewURL(mockCommonDubboUrl)
+ invoker := NewBaseInvoker(url)
+
+ // Clear initial state
+ GetAndRefreshState()
+
+ // After setting unhealthy status, it should be true
+ SetInvokerUnhealthyStatus(invoker)
+ state := GetAndRefreshState()
+ assert.True(t, state)
+
+ // After getting, it should be false again
+ state = GetAndRefreshState()
+ assert.False(t, state)
+
+ // Test state change again
+ RemoveInvokerUnhealthyStatus(invoker)
+ state = GetAndRefreshState()
+ assert.True(t, state)
+
+ state = GetAndRefreshState()
+ assert.False(t, state)
+}
+
+func TestTryRefreshBlackList(t *testing.T) {
+ defer CleanAllStatus()
+
+ url1, _ := common.NewURL(mockCommonDubboUrl)
+ url2, _ :=
common.NewURL("dubbo://localhost:20001/com.ikurento.user.UserProvider")
+
+ invoker1 := NewBaseInvoker(url1)
+ invoker2 := NewBaseInvoker(url2)
+
+ // Add invokers to black list
+ SetInvokerUnhealthyStatus(invoker1)
+ SetInvokerUnhealthyStatus(invoker2)
+
+ assert.False(t, GetInvokerHealthyStatus(invoker1))
+ assert.False(t, GetInvokerHealthyStatus(invoker2))
+
+ // Try refresh black list - since invokers are available, they should
be removed
+ TryRefreshBlackList()
+
+ // Give goroutines time to complete
+ // Note: In real scenario, invokers would be checked for availability
+ // Since our mock invokers are always available, they should be removed
+
+ // Verify black list was processed
+ blackList := GetBlackListInvokers(10)
+ // The behavior depends on the actual IsAvailable() implementation
+ assert.NotNil(t, blackList)
+}
+
+func TestMultipleMethodsStatus(t *testing.T) {
+ defer CleanAllStatus()
+
+ url, _ := common.NewURL(mockCommonDubboUrl)
+
+ // Test multiple methods on same URL
+ request(url, "method1", 100, false, true)
+ request(url, "method2", 200, false, true)
+ request(url, "method3", 150, false, false)
+
+ method1Status := GetMethodStatus(url, "method1")
+ method2Status := GetMethodStatus(url, "method2")
+ method3Status := GetMethodStatus(url, "method3")
+ urlStatus := GetURLStatus(url)
+
+ // Verify individual method stats
+ assert.Equal(t, int32(1), method1Status.GetTotal())
+ assert.Equal(t, int64(100), method1Status.GetTotalElapsed())
+
+ assert.Equal(t, int32(1), method2Status.GetTotal())
+ assert.Equal(t, int64(200), method2Status.GetTotalElapsed())
+ assert.Equal(t, int64(200), method2Status.GetMaxElapsed())
+
+ assert.Equal(t, int32(1), method3Status.GetTotal())
+ assert.Equal(t, int32(1), method3Status.GetFailed())
+
+ // Verify URL aggregates all methods
+ assert.Equal(t, int32(3), urlStatus.GetTotal())
+ assert.Equal(t, int64(450), urlStatus.GetTotalElapsed())
+ assert.Equal(t, int32(1), urlStatus.GetFailed())
+}