github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/dynamic-timeouts_test.go (about) 1 // Copyright (c) 2015-2021 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package cmd 19 20 import ( 21 "math/rand" 22 "runtime" 23 "sync" 24 "testing" 25 "time" 26 ) 27 28 func TestDynamicTimeoutSingleIncrease(t *testing.T) { 29 timeout := newDynamicTimeout(time.Minute, time.Second) 30 31 initial := timeout.Timeout() 32 33 for i := 0; i < dynamicTimeoutLogSize; i++ { 34 timeout.LogFailure() 35 } 36 37 adjusted := timeout.Timeout() 38 39 if initial >= adjusted { 40 t.Errorf("Failure to increase timeout, expected %v to be more than %v", adjusted, initial) 41 } 42 } 43 44 func TestDynamicTimeoutDualIncrease(t *testing.T) { 45 timeout := newDynamicTimeout(time.Minute, time.Second) 46 47 initial := timeout.Timeout() 48 49 for i := 0; i < dynamicTimeoutLogSize; i++ { 50 timeout.LogFailure() 51 } 52 53 adjusted := timeout.Timeout() 54 55 for i := 0; i < dynamicTimeoutLogSize; i++ { 56 timeout.LogFailure() 57 } 58 59 adjustedAgain := timeout.Timeout() 60 61 if initial >= adjusted || adjusted >= adjustedAgain { 62 t.Errorf("Failure to increase timeout multiple times") 63 } 64 } 65 66 func TestDynamicTimeoutSingleDecrease(t *testing.T) { 67 timeout := newDynamicTimeout(time.Minute, time.Second) 68 69 initial := timeout.Timeout() 70 71 for i := 0; i < dynamicTimeoutLogSize; i++ { 72 timeout.LogSuccess(20 * time.Second) 73 } 74 75 adjusted := timeout.Timeout() 76 77 if initial <= adjusted { 78 t.Errorf("Failure to decrease timeout, expected %v to be less than %v", adjusted, initial) 79 } 80 } 81 82 func TestDynamicTimeoutDualDecrease(t *testing.T) { 83 timeout := newDynamicTimeout(time.Minute, time.Second) 84 85 initial := timeout.Timeout() 86 87 for i := 0; i < dynamicTimeoutLogSize; i++ { 88 timeout.LogSuccess(20 * time.Second) 89 } 90 91 adjusted := timeout.Timeout() 92 93 for i := 0; i < dynamicTimeoutLogSize; i++ { 94 timeout.LogSuccess(20 * time.Second) 95 } 96 97 adjustedAgain := timeout.Timeout() 98 99 if initial <= adjusted || adjusted <= adjustedAgain { 100 t.Errorf("Failure to decrease timeout multiple times, initial: %v, adjusted: %v, again: %v", initial, adjusted, adjustedAgain) 101 } 102 } 103 104 func TestDynamicTimeoutManyDecreases(t *testing.T) { 105 timeout := newDynamicTimeout(time.Minute, time.Second) 106 107 initial := timeout.Timeout() 108 109 const successTimeout = 20 * time.Second 110 for l := 0; l < 100; l++ { 111 for i := 0; i < dynamicTimeoutLogSize; i++ { 112 timeout.LogSuccess(successTimeout) 113 } 114 } 115 116 adjusted := timeout.Timeout() 117 // Check whether eventual timeout is between initial value and success timeout 118 if initial <= adjusted || adjusted <= successTimeout { 119 t.Errorf("Failure to decrease timeout appropriately") 120 } 121 } 122 123 func TestDynamicTimeoutConcurrent(t *testing.T) { 124 // Race test. 125 timeout := newDynamicTimeout(time.Second, time.Millisecond) 126 var wg sync.WaitGroup 127 for i := 0; i < runtime.GOMAXPROCS(0); i++ { 128 wg.Add(1) 129 rng := rand.New(rand.NewSource(int64(i))) 130 go func() { 131 defer wg.Done() 132 for i := 0; i < 100; i++ { 133 for j := 0; j < 100; j++ { 134 timeout.LogSuccess(time.Duration(float64(time.Second) * rng.Float64())) 135 } 136 to := timeout.Timeout() 137 if to < time.Millisecond || to > time.Second { 138 panic(to) 139 } 140 } 141 }() 142 } 143 wg.Wait() 144 } 145 146 func TestDynamicTimeoutHitMinimum(t *testing.T) { 147 const minimum = 30 * time.Second 148 timeout := newDynamicTimeout(time.Minute, minimum) 149 150 initial := timeout.Timeout() 151 152 const successTimeout = 20 * time.Second 153 for l := 0; l < 100; l++ { 154 for i := 0; i < dynamicTimeoutLogSize; i++ { 155 timeout.LogSuccess(successTimeout) 156 } 157 } 158 159 adjusted := timeout.Timeout() 160 // Check whether eventual timeout has hit the minimum value 161 if initial <= adjusted || adjusted != minimum { 162 t.Errorf("Failure to decrease timeout appropriately") 163 } 164 } 165 166 func testDynamicTimeoutAdjust(t *testing.T, timeout *dynamicTimeout, f func() float64) { 167 const successTimeout = 20 * time.Second 168 169 for i := 0; i < dynamicTimeoutLogSize; i++ { 170 171 rnd := f() 172 duration := time.Duration(float64(successTimeout) * rnd) 173 174 if duration < 100*time.Millisecond { 175 duration = 100 * time.Millisecond 176 } 177 if duration >= time.Minute { 178 timeout.LogFailure() 179 } else { 180 timeout.LogSuccess(duration) 181 } 182 } 183 } 184 185 func TestDynamicTimeoutAdjustExponential(t *testing.T) { 186 timeout := newDynamicTimeout(time.Minute, time.Second) 187 188 rand.Seed(0) 189 190 initial := timeout.Timeout() 191 192 for try := 0; try < 10; try++ { 193 testDynamicTimeoutAdjust(t, timeout, rand.ExpFloat64) 194 } 195 196 adjusted := timeout.Timeout() 197 if initial <= adjusted { 198 t.Errorf("Failure to decrease timeout, expected %v to be less than %v", adjusted, initial) 199 } 200 } 201 202 func TestDynamicTimeoutAdjustNormalized(t *testing.T) { 203 timeout := newDynamicTimeout(time.Minute, time.Second) 204 205 rand.Seed(0) 206 207 initial := timeout.Timeout() 208 209 for try := 0; try < 10; try++ { 210 testDynamicTimeoutAdjust(t, timeout, func() float64 { 211 return 1.0 + rand.NormFloat64() 212 }) 213 } 214 215 adjusted := timeout.Timeout() 216 if initial <= adjusted { 217 t.Errorf("Failure to decrease timeout, expected %v to be less than %v", adjusted, initial) 218 } 219 }