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 95520ff25 test: add test cases for `filter` (#3118)
95520ff25 is described below
commit 95520ff257079bacc4ba443b06f88662d0810748
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)
+}