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  }