This is an automated email from the ASF dual-hosted git repository.

alexstocks pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/dubbo-go.git

commit 53d5b516deeaf9dd28bd7ee19dab0ae50d6212f3
Author: Xuetao Li <[email protected]>
AuthorDate: Mon Dec 22 07:52:50 2025 +0800

    test: add test cases for `filter` (#3118)
    
    * test: add unit tests for ./filter/
---
 filter/access_key_test.go                        |  47 ++++++++
 filter/adaptivesvc/filter_test.go                | 130 +++++++++++++++++++++++
 filter/adaptivesvc/limiter/hill_climbing_test.go |  89 ++++++++++++++++
 filter/adaptivesvc/limiter/utils_test.go         |  44 ++++++++
 filter/adaptivesvc/limiter_mapper_test.go        |  71 +++++++++++++
 filter/generic/util_test.go                      |  92 ++++++++++++++++
 6 files changed, 473 insertions(+)

diff --git a/filter/access_key_test.go b/filter/access_key_test.go
new file mode 100644
index 000000000..01d47f471
--- /dev/null
+++ b/filter/access_key_test.go
@@ -0,0 +1,47 @@
+/*
+ * 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 filter
+
+import (
+       "testing"
+)
+
+import (
+       "github.com/stretchr/testify/assert"
+)
+
+// Mock the AccessKeyStorage interface
+func TestAccessKeyPair(t *testing.T) {
+       // Test case 1: Test that AccessKeyPair can be properly instantiated 
and fields are correctly set
+       accessKeyPair := &AccessKeyPair{
+               AccessKey:    "test-access-key",
+               SecretKey:    "test-secret-key",
+               ConsumerSide: "consumer-side",
+               ProviderSide: "provider-side",
+               Creator:      "creator",
+               Options:      "options",
+       }
+
+       // Assert that the fields are correctly set
+       assert.Equal(t, "test-access-key", accessKeyPair.AccessKey)
+       assert.Equal(t, "test-secret-key", accessKeyPair.SecretKey)
+       assert.Equal(t, "consumer-side", accessKeyPair.ConsumerSide)
+       assert.Equal(t, "provider-side", accessKeyPair.ProviderSide)
+       assert.Equal(t, "creator", accessKeyPair.Creator)
+       assert.Equal(t, "options", accessKeyPair.Options)
+}
diff --git a/filter/adaptivesvc/filter_test.go 
b/filter/adaptivesvc/filter_test.go
new file mode 100644
index 000000000..c95f6dffd
--- /dev/null
+++ b/filter/adaptivesvc/filter_test.go
@@ -0,0 +1,130 @@
+/*
+ * 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 adaptivesvc
+
+import (
+       "context"
+       "testing"
+)
+
+import (
+       "github.com/golang/mock/gomock"
+
+       "github.com/stretchr/testify/assert"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common"
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+       "dubbo.apache.org/dubbo-go/v3/filter/adaptivesvc/limiter"
+       "dubbo.apache.org/dubbo-go/v3/protocol/invocation"
+       "dubbo.apache.org/dubbo-go/v3/protocol/mock"
+       "dubbo.apache.org/dubbo-go/v3/protocol/result"
+)
+
+type mockUpdater struct {
+       called bool
+}
+
+func (m *mockUpdater) DoUpdate() error {
+       m.called = true
+       return nil
+}
+
+func (m *mockUpdater) Report(_ uint64) {}
+
+func TestAdaptiveServiceProviderFilter_Invoke(t *testing.T) {
+       ctrl := gomock.NewController(t)
+       defer ctrl.Finish()
+
+       u, _ := common.NewURL("dubbo://127.0.0.1:20000/com.test.Service")
+       methodName := "GetInfo"
+       filter := newAdaptiveServiceProviderFilter()
+
+       t.Run("AdaptiveDisabled", func(t *testing.T) {
+               invoc := invocation.NewRPCInvocation(methodName, nil, nil)
+               invoker := mock.NewMockInvoker(ctrl)
+               invoker.EXPECT().Invoke(gomock.Any(), 
gomock.Any()).Return(&result.RPCResult{Rest: "ok"})
+
+               res := filter.Invoke(context.Background(), invoker, invoc)
+               assert.Nil(t, res.Error())
+       })
+
+       t.Run("AdaptiveEnabled_AcquireSuccess", func(t *testing.T) {
+               invoc := invocation.NewRPCInvocation(methodName, nil, 
map[string]any{
+                       constant.AdaptiveServiceEnabledKey: 
constant.AdaptiveServiceIsEnabled,
+               })
+               invoker := mock.NewMockInvoker(ctrl)
+               invoker.EXPECT().GetURL().Return(u).AnyTimes()
+               invoker.EXPECT().Invoke(gomock.Any(), 
gomock.Any()).Return(&result.RPCResult{Rest: "ok"})
+
+               res := filter.Invoke(context.Background(), invoker, invoc)
+               assert.Nil(t, res.Error())
+
+               updater, _ := 
invoc.GetAttribute(constant.AdaptiveServiceUpdaterKey)
+               assert.NotNil(t, updater)
+       })
+}
+
+func TestAdaptiveServiceProviderFilter_OnResponse(t *testing.T) {
+       ctrl := gomock.NewController(t)
+       defer ctrl.Finish()
+
+       u, _ := common.NewURL("dubbo://127.0.0.1:20000/com.test.Service")
+       methodName := "GetInfo"
+       filter := newAdaptiveServiceProviderFilter()
+
+       t.Run("DisabledInResponse", func(t *testing.T) {
+               invoc := invocation.NewRPCInvocation(methodName, nil, nil)
+               res := &result.RPCResult{Rest: "ok"}
+               invoker := mock.NewMockInvoker(ctrl)
+
+               ret := filter.OnResponse(context.Background(), res, invoker, 
invoc)
+               assert.Equal(t, res, ret)
+       })
+
+       t.Run("InterruptedErrorShouldSkip", func(t *testing.T) {
+               invoc := invocation.NewRPCInvocation(methodName, nil, nil)
+               res := &result.RPCResult{Err: 
wrapErrAdaptiveSvcInterrupted("limit exceeded")}
+               invoker := mock.NewMockInvoker(ctrl)
+
+               ret := filter.OnResponse(context.Background(), res, invoker, 
invoc)
+               assert.True(t, isErrAdaptiveSvcInterrupted(ret.Error()))
+       })
+
+       t.Run("SuccessWithAttachments", func(t *testing.T) {
+               invoc := invocation.NewRPCInvocation(methodName, nil, nil)
+               updater := &mockUpdater{}
+               invoc.SetAttribute(constant.AdaptiveServiceUpdaterKey, updater)
+
+               res := &result.RPCResult{Rest: "ok"}
+               res.AddAttachment(constant.AdaptiveServiceEnabledKey, 
constant.AdaptiveServiceIsEnabled)
+
+               invoker := mock.NewMockInvoker(ctrl)
+               invoker.EXPECT().GetURL().Return(u).AnyTimes()
+
+               _, _ = limiterMapperSingleton.newAndSetMethodLimiter(u, 
methodName, limiter.HillClimbingLimiter)
+
+               ret := filter.OnResponse(context.Background(), res, invoker, 
invoc)
+
+               assert.Nil(t, ret.Error())
+               assert.NotEmpty(t, 
ret.Attachment(constant.AdaptiveServiceRemainingKey, ""))
+               assert.NotEmpty(t, 
ret.Attachment(constant.AdaptiveServiceInflightKey, ""))
+               assert.True(t, updater.called)
+       })
+}
diff --git a/filter/adaptivesvc/limiter/hill_climbing_test.go 
b/filter/adaptivesvc/limiter/hill_climbing_test.go
new file mode 100644
index 000000000..7ad75666c
--- /dev/null
+++ b/filter/adaptivesvc/limiter/hill_climbing_test.go
@@ -0,0 +1,89 @@
+/*
+ * 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 limiter
+
+import (
+       "testing"
+)
+
+import (
+       "github.com/stretchr/testify/assert"
+)
+
+// Test for HillClimbing limiter's Acquire method
+func TestHillClimbing_Acquire(t *testing.T) {
+       limiter := NewHillClimbing().(*HillClimbing)
+
+       // Simulating that there is remaining capacity
+       limiter.limitation.Store(100)
+       limiter.inflight.Store(50)
+
+       updater, err := limiter.Acquire()
+       assert.NotNil(t, updater)
+       assert.NoError(t, err)
+
+       // Simulating no remaining capacity
+       limiter.limitation.Store(50)
+       limiter.inflight.Store(50)
+
+       updater, err = limiter.Acquire()
+       assert.Nil(t, updater)
+       assert.Error(t, err, ErrReachLimitation)
+}
+
+// Test the HillClimbingUpdater's DoUpdate method
+func TestHillClimbingUpdater_DoUpdate(t *testing.T) {
+       limiter := NewHillClimbing().(*HillClimbing)
+       updater := NewHillClimbingUpdater(limiter)
+
+       // Simulate the limiter update with arbitrary values for RTT and 
inflight
+       // Normally, this would adjust the limiter's limitation based on RTT 
and inflight metrics
+       err := updater.DoUpdate()
+       assert.NoError(t, err)
+}
+
+// Test adjustLimitation method with different options
+func TestHillClimbingUpdater_AdjustLimitation(t *testing.T) {
+       limiter := NewHillClimbing().(*HillClimbing)
+       updater := NewHillClimbingUpdater(limiter)
+
+       // Simulate a scenario where the limiter is set to extend its capacity
+       err := updater.adjustLimitation(HillClimbingOptionExtend)
+       assert.NoError(t, err)
+       assert.True(t, limiter.limitation.Load() > initialLimitation)
+
+       // Simulate a scenario where the limiter is set to shrink its capacity
+       err = updater.adjustLimitation(HillClimbingOptionShrink)
+       assert.NoError(t, err)
+       assert.True(t, limiter.limitation.Load() < initialLimitation)
+}
+
+// Test HillClimbing's Remaining capacity behavior
+func TestHillClimbing_Remaining(t *testing.T) {
+       limiter := NewHillClimbing().(*HillClimbing)
+       limiter.limitation.Store(100)
+       limiter.inflight.Store(30)
+
+       remaining := limiter.Remaining()
+       assert.Equal(t, uint64(70), remaining)
+
+       // Simulate that inflight requests exceed the limitation
+       limiter.inflight.Store(120)
+       remaining = limiter.Remaining()
+       assert.Equal(t, uint64(0), remaining)
+}
diff --git a/filter/adaptivesvc/limiter/utils_test.go 
b/filter/adaptivesvc/limiter/utils_test.go
new file mode 100644
index 000000000..483056487
--- /dev/null
+++ b/filter/adaptivesvc/limiter/utils_test.go
@@ -0,0 +1,44 @@
+/*
+ * 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 limiter
+
+import (
+       "testing"
+       "time"
+)
+
+import (
+       "github.com/stretchr/testify/assert"
+)
+
+func TestMinDuration(t *testing.T) {
+       // Test when lhs is smaller than rhs
+       dur1 := 2 * time.Second
+       dur2 := 3 * time.Second
+       result := minDuration(dur1, dur2)
+       assert.Equal(t, dur1, result)
+
+       // Test when rhs is smaller than lhs
+       result = minDuration(dur2, dur1)
+       assert.Equal(t, dur1, result)
+
+       // Test when both durations are equal
+       dur3 := 2 * time.Second
+       result = minDuration(dur3, dur3)
+       assert.Equal(t, dur3, result)
+}
diff --git a/filter/adaptivesvc/limiter_mapper_test.go 
b/filter/adaptivesvc/limiter_mapper_test.go
new file mode 100644
index 000000000..13ef47f82
--- /dev/null
+++ b/filter/adaptivesvc/limiter_mapper_test.go
@@ -0,0 +1,71 @@
+/*
+ * 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 adaptivesvc
+
+import (
+       "testing"
+)
+
+import (
+       "github.com/stretchr/testify/assert"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common"
+       "dubbo.apache.org/dubbo-go/v3/filter/adaptivesvc/limiter"
+)
+
+func TestLimiterMapper_newAndSetMethodLimiter(t *testing.T) {
+       // Initialize the limiterMapper and mock URL
+       mapper := newLimiterMapper()
+       url := &common.URL{Path: "/testService"}
+       methodName := "testMethod"
+
+       // Test creating a new limiter
+       l, err := mapper.newAndSetMethodLimiter(url, methodName, 
limiter.HillClimbingLimiter)
+       assert.NoError(t, err)
+       assert.NotNil(t, l)
+
+       // Test that the same limiter is returned if already created
+       l2, err := mapper.newAndSetMethodLimiter(url, methodName, 
limiter.HillClimbingLimiter)
+       assert.NoError(t, err)
+       assert.Same(t, l, l2)
+}
+
+func TestLimiterMapper_getMethodLimiter(t *testing.T) {
+       // Initialize the limiterMapper and mock URL
+       mapper := newLimiterMapper()
+       url := &common.URL{Path: "/testService"}
+       methodName := "testMethod"
+
+       // Add a limiter to the mapper
+       _, err := mapper.newAndSetMethodLimiter(url, methodName, 
limiter.HillClimbingLimiter)
+       assert.NoError(t, err)
+
+       // Test getting an existing limiter
+       l, err := mapper.getMethodLimiter(url, methodName)
+       assert.NoError(t, err)
+       assert.NotNil(t, l)
+
+       // Test getting a limiter that does not exist
+       url2 := &common.URL{Path: "/testService2"}
+       l, err = mapper.getMethodLimiter(url2, "nonExistentMethod")
+       assert.Error(t, err)
+       assert.Nil(t, l)
+       assert.Equal(t, ErrLimiterNotFoundOnMapper, err)
+}
diff --git a/filter/generic/util_test.go b/filter/generic/util_test.go
new file mode 100644
index 000000000..5fdc066c1
--- /dev/null
+++ b/filter/generic/util_test.go
@@ -0,0 +1,92 @@
+/*
+ * 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 generic
+
+import (
+       "testing"
+)
+
+import (
+       "github.com/golang/mock/gomock"
+
+       "github.com/stretchr/testify/assert"
+)
+
+import (
+       "dubbo.apache.org/dubbo-go/v3/common"
+       "dubbo.apache.org/dubbo-go/v3/common/constant"
+       "dubbo.apache.org/dubbo-go/v3/filter/generic/generalizer"
+       "dubbo.apache.org/dubbo-go/v3/protocol/invocation"
+       "dubbo.apache.org/dubbo-go/v3/protocol/mock"
+)
+
+func TestIsCallingToGenericService(t *testing.T) {
+       ctrl := gomock.NewController(t)
+       defer ctrl.Finish()
+
+       u1, _ := common.NewURL("dubbo://127.0.0.1:20000/ComTest?generic=true")
+       invoker1 := mock.NewMockInvoker(ctrl)
+       invoker1.EXPECT().GetURL().Return(u1).AnyTimes()
+       invoc1 := invocation.NewRPCInvocation("GetUser", []any{"ID"}, nil)
+       assert.True(t, isCallingToGenericService(invoker1, invoc1))
+
+       u2, _ := common.NewURL("dubbo://127.0.0.1:20000/ComTest")
+       invoker2 := mock.NewMockInvoker(ctrl)
+       invoker2.EXPECT().GetURL().Return(u2).AnyTimes()
+       assert.False(t, isCallingToGenericService(invoker2, invoc1))
+
+       invoc3 := invocation.NewRPCInvocation(constant.Generic, []any{"m", "t", 
"a"}, nil)
+       assert.False(t, isCallingToGenericService(invoker1, invoc3))
+}
+
+func TestIsMakingAGenericCall(t *testing.T) {
+       ctrl := gomock.NewController(t)
+       defer ctrl.Finish()
+
+       u, _ := common.NewURL("dubbo://127.0.0.1:20000/ComTest?generic=true")
+       invoker := mock.NewMockInvoker(ctrl)
+       invoker.EXPECT().GetURL().Return(u).AnyTimes()
+
+       invoc1 := invocation.NewRPCInvocation(constant.Generic, []any{"method", 
"types", "args"}, nil)
+       assert.True(t, isMakingAGenericCall(invoker, invoc1))
+
+       invoc2 := invocation.NewRPCInvocation(constant.Generic, 
[]any{"method"}, nil)
+       assert.False(t, isMakingAGenericCall(invoker, invoc2))
+
+       invoc3 := invocation.NewRPCInvocation("GetUser", []any{"a", "b", "c"}, 
nil)
+       assert.False(t, isMakingAGenericCall(invoker, invoc3))
+}
+
+func TestIsGeneric(t *testing.T) {
+       assert.True(t, isGeneric("true"))
+       assert.True(t, isGeneric("True"))
+       assert.False(t, isGeneric("false"))
+       assert.False(t, isGeneric(""))
+       assert.False(t, isGeneric("bean")) // 目前代码逻辑仅匹配 "true"
+}
+
+func TestGetGeneralizer(t *testing.T) {
+       g1 := getGeneralizer(constant.GenericSerializationDefault)
+       assert.IsType(t, generalizer.GetMapGeneralizer(), g1)
+
+       g2 := getGeneralizer(constant.GenericSerializationGson)
+       assert.IsType(t, generalizer.GetGsonGeneralizer(), g2)
+
+       g3 := getGeneralizer("unsupported_type")
+       assert.IsType(t, generalizer.GetMapGeneralizer(), g3)
+}

Reply via email to