dubbo.apache.org/dubbo-go/v3@v3.1.1/filter/hystrix/filter_test.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package hystrix 19 20 import ( 21 "context" 22 "fmt" 23 "regexp" 24 "testing" 25 ) 26 27 import ( 28 "github.com/afex/hystrix-go/hystrix" 29 30 "github.com/pkg/errors" 31 32 "github.com/stretchr/testify/assert" 33 ) 34 35 import ( 36 "dubbo.apache.org/dubbo-go/v3/common" 37 "dubbo.apache.org/dubbo-go/v3/common/constant" 38 "dubbo.apache.org/dubbo-go/v3/protocol" 39 "dubbo.apache.org/dubbo-go/v3/protocol/invocation" 40 ) 41 42 func init() { 43 mockInitHystrixConfig() 44 } 45 46 func TestNewHystrixFilterError(t *testing.T) { 47 get := NewHystrixFilterError(errors.New("test"), true) 48 assert.True(t, get.(*FilterError).FailByHystrix()) 49 assert.Equal(t, "test", get.Error()) 50 } 51 52 func mockInitHystrixConfig() { 53 // Mock config 54 confConsumer = &FilterConfig{ 55 make(map[string]*CommandConfigWithError), 56 "Default", 57 make(map[string]ServiceHystrixConfig), 58 } 59 confConsumer.Configs["Default"] = &CommandConfigWithError{ 60 Timeout: 1000, 61 MaxConcurrentRequests: 600, 62 RequestVolumeThreshold: 5, 63 SleepWindow: 5000, 64 ErrorPercentThreshold: 5, 65 Error: nil, 66 } 67 confConsumer.Configs["userp"] = &CommandConfigWithError{ 68 Timeout: 2000, 69 MaxConcurrentRequests: 64, 70 RequestVolumeThreshold: 15, 71 SleepWindow: 4000, 72 ErrorPercentThreshold: 45, 73 Error: nil, 74 } 75 confConsumer.Configs["userp_m"] = &CommandConfigWithError{ 76 Timeout: 1200, 77 MaxConcurrentRequests: 64, 78 RequestVolumeThreshold: 5, 79 SleepWindow: 6000, 80 ErrorPercentThreshold: 60, 81 Error: []string{ 82 "exception", 83 }, 84 } 85 confConsumer.Services["com.ikurento.user.UserProvider"] = ServiceHystrixConfig{ 86 "userp", 87 map[string]string{ 88 "GetUser": "userp_m", 89 }, 90 } 91 } 92 93 func TestGetHystrixFilter(t *testing.T) { 94 filterGot := newFilterConsumer() 95 assert.NotNil(t, filterGot) 96 } 97 98 func TestGetConfig1(t *testing.T) { 99 mockInitHystrixConfig() 100 configGot := getConfig("com.ikurento.user.UserProvider", "GetUser", true) 101 assert.NotNil(t, configGot) 102 assert.Equal(t, 1200, configGot.Timeout) 103 assert.Equal(t, 64, configGot.MaxConcurrentRequests) 104 assert.Equal(t, 6000, configGot.SleepWindow) 105 assert.Equal(t, 60, configGot.ErrorPercentThreshold) 106 assert.Equal(t, 5, configGot.RequestVolumeThreshold) 107 } 108 109 func TestGetConfig2(t *testing.T) { 110 mockInitHystrixConfig() 111 configGot := getConfig("com.ikurento.user.UserProvider", "GetUser0", true) 112 assert.NotNil(t, configGot) 113 assert.Equal(t, 2000, configGot.Timeout) 114 assert.Equal(t, 64, configGot.MaxConcurrentRequests) 115 assert.Equal(t, 4000, configGot.SleepWindow) 116 assert.Equal(t, 45, configGot.ErrorPercentThreshold) 117 assert.Equal(t, 15, configGot.RequestVolumeThreshold) 118 } 119 120 func TestGetConfig3(t *testing.T) { 121 mockInitHystrixConfig() 122 // This should use default 123 configGot := getConfig("Mock.Service", "GetMock", true) 124 assert.NotNil(t, configGot) 125 assert.Equal(t, 1000, configGot.Timeout) 126 assert.Equal(t, 600, configGot.MaxConcurrentRequests) 127 assert.Equal(t, 5000, configGot.SleepWindow) 128 assert.Equal(t, 5, configGot.ErrorPercentThreshold) 129 assert.Equal(t, 5, configGot.RequestVolumeThreshold) 130 } 131 132 type testMockSuccessInvoker struct { 133 protocol.BaseInvoker 134 } 135 136 func (iv *testMockSuccessInvoker) Invoke(_ context.Context, _ protocol.Invocation) protocol.Result { 137 return &protocol.RPCResult{ 138 Rest: "Success", 139 Err: nil, 140 } 141 } 142 143 type testMockFailInvoker struct { 144 protocol.BaseInvoker 145 } 146 147 func (iv *testMockFailInvoker) Invoke(_ context.Context, _ protocol.Invocation) protocol.Result { 148 return &protocol.RPCResult{ 149 Err: errors.Errorf("exception"), 150 } 151 } 152 153 func TestHystrixFilterInvokeSuccess(t *testing.T) { 154 hf := &Filter{} 155 testUrl, err := common.NewURL( 156 fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LocalHostValue, constant.DefaultPort)) 157 assert.NoError(t, err) 158 testInvoker := testMockSuccessInvoker{*protocol.NewBaseInvoker(testUrl)} 159 result := hf.Invoke(context.Background(), &testInvoker, &invocation.RPCInvocation{}) 160 assert.NotNil(t, result) 161 assert.NoError(t, result.Error()) 162 assert.NotNil(t, result.Result()) 163 } 164 165 func TestHystrixFilterInvokeFail(t *testing.T) { 166 hf := &Filter{} 167 testUrl, err := common.NewURL( 168 fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LocalHostValue, constant.DefaultPort)) 169 assert.NoError(t, err) 170 testInvoker := testMockFailInvoker{*protocol.NewBaseInvoker(testUrl)} 171 result := hf.Invoke(context.Background(), &testInvoker, &invocation.RPCInvocation{}) 172 assert.NotNil(t, result) 173 assert.Error(t, result.Error()) 174 } 175 176 func TestHystricFilterInvokeCircuitBreak(t *testing.T) { 177 mockInitHystrixConfig() 178 hystrix.Flush() 179 hf := &Filter{COrP: true} 180 resChan := make(chan protocol.Result, 50) 181 for i := 0; i < 50; i++ { 182 go func() { 183 testUrl, err := common.NewURL( 184 fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LocalHostValue, constant.DefaultPort)) 185 assert.NoError(t, err) 186 testInvoker := testMockSuccessInvoker{*protocol.NewBaseInvoker(testUrl)} 187 result := hf.Invoke(context.Background(), &testInvoker, &invocation.RPCInvocation{}) 188 resChan <- result 189 }() 190 } 191 // This can not always pass the test when on travis due to concurrency, you can uncomment the code below and test it locally 192 193 //var lastRest bool 194 //for i := 0; i < 50; i++ { 195 // lastRest = (<-resChan).Error().(*FilterError).FailByHystrix() 196 //} 197 //Normally the last result should be true, which means the circuit has been opened 198 // 199 //assert.True(t, lastRest) 200 } 201 202 func TestHystricFilterInvokeCircuitBreakOmitException(t *testing.T) { 203 mockInitHystrixConfig() 204 hystrix.Flush() 205 reg, _ := regexp.Compile(".*exception.*") 206 regs := []*regexp.Regexp{reg} 207 hf := &Filter{res: map[string][]*regexp.Regexp{"": regs}, COrP: true} 208 resChan := make(chan protocol.Result, 50) 209 for i := 0; i < 50; i++ { 210 go func() { 211 testUrl, err := common.NewURL( 212 fmt.Sprintf("dubbo://%s:%d/com.ikurento.user.UserProvider", constant.LocalHostValue, constant.DefaultPort)) 213 assert.NoError(t, err) 214 testInvoker := testMockSuccessInvoker{*protocol.NewBaseInvoker(testUrl)} 215 result := hf.Invoke(context.Background(), &testInvoker, &invocation.RPCInvocation{}) 216 resChan <- result 217 }() 218 } 219 // This can not always pass the test when on travis due to concurrency, you can uncomment the code below and test it locally 220 221 //time.Sleep(time.Second * 6) 222 //var lastRest bool 223 //for i := 0; i < 50; i++ { 224 // lastRest = (<-resChan).Error().(*FilterError).FailByHystrix() 225 //} 226 // 227 //assert.False(t, lastRest) 228 } 229 230 func TestGetHystrixFilterConsumer(t *testing.T) { 231 get := newFilterConsumer() 232 assert.NotNil(t, get) 233 assert.True(t, get.(*Filter).COrP) 234 } 235 236 func TestGetHystrixFilterProvider(t *testing.T) { 237 get := newFilterProvider() 238 assert.NotNil(t, get) 239 assert.False(t, get.(*Filter).COrP) 240 }