github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/pkg/backoff/backoff_test.go (about)

     1  // Copyright 2019 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package backoff
    15  
    16  import (
    17  	"math"
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/pingcap/tiflow/dm/pkg/terror"
    22  	"github.com/stretchr/testify/require"
    23  )
    24  
    25  func TestNewBackoff(t *testing.T) {
    26  	t.Parallel()
    27  	var (
    28  		backoffFactor float64 = 2
    29  		backoffMin            = 1 * time.Second
    30  		backoffMax            = 5 * time.Minute
    31  		backoffJitter         = true
    32  		bf            *Backoff
    33  		err           error
    34  	)
    35  	testCases := []struct {
    36  		factor float64
    37  		jitter bool
    38  		min    time.Duration
    39  		max    time.Duration
    40  		hasErr bool
    41  	}{
    42  		{backoffFactor, backoffJitter, backoffMin, backoffMax, false},
    43  		{0, backoffJitter, backoffMin, backoffMax, true},
    44  		{-1, backoffJitter, backoffMin, backoffMax, true},
    45  		{backoffFactor, backoffJitter, -1, backoffMax, true},
    46  		{backoffFactor, backoffJitter, backoffMin, -1, true},
    47  		{backoffFactor, backoffJitter, backoffMin, backoffMin - 1, true},
    48  	}
    49  	for _, tc := range testCases {
    50  		bf, err = NewBackoff(tc.factor, tc.jitter, tc.min, tc.max)
    51  		if tc.hasErr {
    52  			require.Nil(t, bf)
    53  			require.True(t, terror.ErrBackoffArgsNotValid.Equal(err))
    54  		} else {
    55  			require.NoError(t, err)
    56  		}
    57  	}
    58  }
    59  
    60  func TestExponentialBackoff(t *testing.T) {
    61  	t.Parallel()
    62  	var (
    63  		min            = 1 * time.Millisecond
    64  		max            = 1 * time.Second
    65  		factor float64 = 2
    66  	)
    67  	b := &Backoff{
    68  		Min:    min,
    69  		Max:    max,
    70  		Factor: factor,
    71  	}
    72  
    73  	for i := 0; i < 10; i++ {
    74  		expected := min * time.Duration(math.Pow(factor, float64(i)))
    75  		require.Equal(t, expected, b.Duration())
    76  	}
    77  	b.Rollback()
    78  	require.Equal(t, 512*min, b.Current())
    79  	b.Forward()
    80  	for i := 0; i < 10; i++ {
    81  		require.Equal(t, max, b.Duration())
    82  	}
    83  	b.Reset()
    84  	require.Equal(t, min, b.Duration())
    85  }
    86  
    87  func checkBetween(t *testing.T, value, low, high time.Duration) {
    88  	t.Helper()
    89  	require.True(t, value > low)
    90  	require.True(t, value < high)
    91  }
    92  
    93  func TestBackoffJitter(t *testing.T) {
    94  	t.Parallel()
    95  	var (
    96  		min            = 1 * time.Millisecond
    97  		max            = 1 * time.Second
    98  		factor float64 = 2
    99  	)
   100  	b := &Backoff{
   101  		Min:    min,
   102  		Max:    max,
   103  		Factor: factor,
   104  		Jitter: true,
   105  	}
   106  	require.Equal(t, min, b.Duration())
   107  	checkBetween(t, b.Duration(), min, 2*min)
   108  	checkBetween(t, b.Duration(), 2*min, 4*min)
   109  	checkBetween(t, b.Duration(), 4*min, 8*min)
   110  	b.Reset()
   111  	require.Equal(t, min, b.Duration())
   112  }
   113  
   114  func TestFixedBackoff(t *testing.T) {
   115  	t.Parallel()
   116  	var (
   117  		min            = 100 * time.Millisecond
   118  		max            = 100 * time.Millisecond
   119  		factor float64 = 2
   120  	)
   121  	b := &Backoff{
   122  		Min:    min,
   123  		Max:    max,
   124  		Factor: factor,
   125  	}
   126  	for i := 0; i < 10; i++ {
   127  		require.Equal(t, max, b.Duration())
   128  	}
   129  }
   130  
   131  func TestOverflowBackoff(t *testing.T) {
   132  	t.Parallel()
   133  	testCases := []struct {
   134  		min    time.Duration
   135  		max    time.Duration
   136  		factor float64
   137  	}{
   138  		{time.Duration(math.MaxInt64/2 + math.MaxInt64/4 + 2), time.Duration(math.MaxInt64), 2},
   139  		{time.Duration(math.MaxInt64/2 + 1), time.Duration(math.MaxInt64), 2},
   140  		{time.Duration(math.MaxInt64), time.Duration(math.MaxInt64), 2},
   141  	}
   142  	for _, tc := range testCases {
   143  		b := &Backoff{
   144  			Min:    tc.min,
   145  			Max:    tc.max,
   146  			Factor: tc.factor,
   147  		}
   148  		require.Equal(t, tc.min, b.Duration())
   149  		require.Equal(t, tc.max, b.Duration())
   150  	}
   151  }
   152  
   153  func TestForward(t *testing.T) {
   154  	t.Parallel()
   155  	var (
   156  		factor float64 = 2
   157  		min            = 1 * time.Second
   158  		max            = 5 * time.Second
   159  		n              = 10
   160  	)
   161  	b := &Backoff{
   162  		Min:    min,
   163  		Max:    max,
   164  		Factor: factor,
   165  	}
   166  	for i := 0; i < n; i++ {
   167  		b.Forward()
   168  	}
   169  	require.Equal(t, n, b.cwnd)
   170  	b.Reset()
   171  	require.Equal(t, 0, b.cwnd)
   172  	for i := 0; i < n; i++ {
   173  		b.BoundaryForward()
   174  	}
   175  	require.Equal(t, 3, b.cwnd)
   176  }