| /* |
| * 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_impl |
| |
| import ( |
| "context" |
| "fmt" |
| "regexp" |
| "testing" |
| ) |
| |
| import ( |
| "github.com/afex/hystrix-go/hystrix" |
| "github.com/pkg/errors" |
| "github.com/stretchr/testify/assert" |
| ) |
| |
| import ( |
| "github.com/apache/dubbo-go/common" |
| "github.com/apache/dubbo-go/common/constant" |
| "github.com/apache/dubbo-go/protocol" |
| "github.com/apache/dubbo-go/protocol/invocation" |
| ) |
| |
| func init() { |
| mockInitHystrixConfig() |
| } |
| |
| func TestNewHystrixFilterError(t *testing.T) { |
| get := NewHystrixFilterError(errors.New("test"), true) |
| assert.True(t, get.(*HystrixFilterError).FailByHystrix()) |
| assert.Equal(t, "test", get.Error()) |
| } |
| |
| func mockInitHystrixConfig() { |
| // Mock config |
| confConsumer = &HystrixFilterConfig{ |
| make(map[string]*CommandConfigWithError), |
| "Default", |
| make(map[string]ServiceHystrixConfig), |
| } |
| confConsumer.Configs["Default"] = &CommandConfigWithError{ |
| Timeout: 1000, |
| MaxConcurrentRequests: 600, |
| RequestVolumeThreshold: 5, |
| SleepWindow: 5000, |
| ErrorPercentThreshold: 5, |
| Error: nil, |
| } |
| confConsumer.Configs["userp"] = &CommandConfigWithError{ |
| Timeout: 2000, |
| MaxConcurrentRequests: 64, |
| RequestVolumeThreshold: 15, |
| SleepWindow: 4000, |
| ErrorPercentThreshold: 45, |
| Error: nil, |
| } |
| confConsumer.Configs["userp_m"] = &CommandConfigWithError{ |
| Timeout: 1200, |
| MaxConcurrentRequests: 64, |
| RequestVolumeThreshold: 5, |
| SleepWindow: 6000, |
| ErrorPercentThreshold: 60, |
| Error: []string{ |
| "exception", |
| }, |
| } |
| confConsumer.Services["com.ikurento.user.UserProvider"] = ServiceHystrixConfig{ |
| "userp", |
| map[string]string{ |
| "GetUser": "userp_m", |
| }, |
| } |
| } |
| |
| func TestGetHystrixFilter(t *testing.T) { |
| filterGot := GetHystrixFilterConsumer() |
| assert.NotNil(t, filterGot) |
| } |
| |
| func TestGetConfig1(t *testing.T) { |
| mockInitHystrixConfig() |
| configGot := getConfig("com.ikurento.user.UserProvider", "GetUser", true) |
| assert.NotNil(t, configGot) |
| assert.Equal(t, 1200, configGot.Timeout) |
| assert.Equal(t, 64, configGot.MaxConcurrentRequests) |
| assert.Equal(t, 6000, configGot.SleepWindow) |
| assert.Equal(t, 60, configGot.ErrorPercentThreshold) |
| assert.Equal(t, 5, configGot.RequestVolumeThreshold) |
| } |
| |
| func TestGetConfig2(t *testing.T) { |
| mockInitHystrixConfig() |
| configGot := getConfig("com.ikurento.user.UserProvider", "GetUser0", true) |
| assert.NotNil(t, configGot) |
| assert.Equal(t, 2000, configGot.Timeout) |
| assert.Equal(t, 64, configGot.MaxConcurrentRequests) |
| assert.Equal(t, 4000, configGot.SleepWindow) |
| assert.Equal(t, 45, configGot.ErrorPercentThreshold) |
| assert.Equal(t, 15, configGot.RequestVolumeThreshold) |
| } |
| |
| func TestGetConfig3(t *testing.T) { |
| mockInitHystrixConfig() |
| // This should use default |
| configGot := getConfig("Mock.Service", "GetMock", true) |
| assert.NotNil(t, configGot) |
| assert.Equal(t, 1000, configGot.Timeout) |
| assert.Equal(t, 600, configGot.MaxConcurrentRequests) |
| assert.Equal(t, 5000, configGot.SleepWindow) |
| assert.Equal(t, 5, configGot.ErrorPercentThreshold) |
| assert.Equal(t, 5, configGot.RequestVolumeThreshold) |
| } |
| |
| type testMockSuccessInvoker struct { |
| protocol.BaseInvoker |
| } |
| |
| func (iv *testMockSuccessInvoker) Invoke(_ context.Context, _ protocol.Invocation) protocol.Result { |
| return &protocol.RPCResult{ |
| Rest: "Success", |
| Err: nil, |
| } |
| } |
| |
| type testMockFailInvoker struct { |
| protocol.BaseInvoker |
| } |
| |
| func (iv *testMockFailInvoker) Invoke(_ context.Context, _ protocol.Invocation) protocol.Result { |
| return &protocol.RPCResult{ |
| Err: errors.Errorf("exception"), |
| } |
| } |
| |
| func TestHystrixFilterInvokeSuccess(t *testing.T) { |
| hf := &HystrixFilter{} |
| testUrl, err := common.NewURL( |
| fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LOCAL_HOST_VALUE, constant.DEFAULT_PORT)) |
| assert.NoError(t, err) |
| testInvoker := testMockSuccessInvoker{*protocol.NewBaseInvoker(testUrl)} |
| result := hf.Invoke(context.Background(), &testInvoker, &invocation.RPCInvocation{}) |
| assert.NotNil(t, result) |
| assert.NoError(t, result.Error()) |
| assert.NotNil(t, result.Result()) |
| } |
| |
| func TestHystrixFilterInvokeFail(t *testing.T) { |
| hf := &HystrixFilter{} |
| testUrl, err := common.NewURL( |
| fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LOCAL_HOST_VALUE, constant.DEFAULT_PORT)) |
| assert.NoError(t, err) |
| testInvoker := testMockFailInvoker{*protocol.NewBaseInvoker(testUrl)} |
| result := hf.Invoke(context.Background(), &testInvoker, &invocation.RPCInvocation{}) |
| assert.NotNil(t, result) |
| assert.Error(t, result.Error()) |
| } |
| |
| func TestHystricFilterInvokeCircuitBreak(t *testing.T) { |
| mockInitHystrixConfig() |
| hystrix.Flush() |
| hf := &HystrixFilter{COrP: true} |
| resChan := make(chan protocol.Result, 50) |
| for i := 0; i < 50; i++ { |
| go func() { |
| testUrl, err := common.NewURL( |
| fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LOCAL_HOST_VALUE, constant.DEFAULT_PORT)) |
| assert.NoError(t, err) |
| testInvoker := testMockSuccessInvoker{*protocol.NewBaseInvoker(testUrl)} |
| result := hf.Invoke(context.Background(), &testInvoker, &invocation.RPCInvocation{}) |
| resChan <- result |
| }() |
| } |
| // This can not always pass the test when on travis due to concurrency, you can uncomment the code below and test it locally |
| |
| //var lastRest bool |
| //for i := 0; i < 50; i++ { |
| // lastRest = (<-resChan).Error().(*HystrixFilterError).FailByHystrix() |
| //} |
| //Normally the last result should be true, which means the circuit has been opened |
| // |
| //assert.True(t, lastRest) |
| } |
| |
| func TestHystricFilterInvokeCircuitBreakOmitException(t *testing.T) { |
| mockInitHystrixConfig() |
| hystrix.Flush() |
| reg, _ := regexp.Compile(".*exception.*") |
| regs := []*regexp.Regexp{reg} |
| hf := &HystrixFilter{res: map[string][]*regexp.Regexp{"": regs}, COrP: true} |
| resChan := make(chan protocol.Result, 50) |
| for i := 0; i < 50; i++ { |
| go func() { |
| testUrl, err := common.NewURL( |
| fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LOCAL_HOST_VALUE, constant.DEFAULT_PORT)) |
| assert.NoError(t, err) |
| testInvoker := testMockSuccessInvoker{*protocol.NewBaseInvoker(testUrl)} |
| result := hf.Invoke(context.Background(), &testInvoker, &invocation.RPCInvocation{}) |
| resChan <- result |
| }() |
| } |
| // This can not always pass the test when on travis due to concurrency, you can uncomment the code below and test it locally |
| |
| //time.Sleep(time.Second * 6) |
| //var lastRest bool |
| //for i := 0; i < 50; i++ { |
| // lastRest = (<-resChan).Error().(*HystrixFilterError).FailByHystrix() |
| //} |
| // |
| //assert.False(t, lastRest) |
| } |
| |
| func TestGetHystrixFilterConsumer(t *testing.T) { |
| get := GetHystrixFilterConsumer() |
| assert.NotNil(t, get) |
| assert.True(t, get.(*HystrixFilter).COrP) |
| } |
| |
| func TestGetHystrixFilterProvider(t *testing.T) { |
| get := GetHystrixFilterProvider() |
| assert.NotNil(t, get) |
| assert.False(t, get.(*HystrixFilter).COrP) |
| } |