github.com/bytedance/gopkg@v0.0.0-20240514070511-01b2cbcf35e1/cloud/circuitbreaker/panel_test.go (about) 1 // Copyright 2021 ByteDance 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 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package circuitbreaker 16 17 import ( 18 "sync" 19 "sync/atomic" 20 "testing" 21 "time" 22 ) 23 24 func testRateTripFuncFalse(rate float64, minSamples int64) TripFunc { 25 return func(m Metricer) bool { 26 samples := m.Samples() 27 _ = samples >= minSamples && m.ErrorRate() >= rate 28 return false 29 } 30 } 31 32 func TestPanel(t *testing.T) { 33 cooling := time.Millisecond * 10 34 35 op := Options{ 36 CoolingTimeout: cooling, 37 ShouldTrip: ConsecutiveTripFunc(1000), 38 } 39 40 p, err := NewPanel(nil, op) 41 assert(t, err == nil) 42 if p == nil { 43 } 44 45 var counter int64 46 var wg sync.WaitGroup 47 worker := func() { 48 for i := 0; i < 10; i++ { 49 if p.IsAllowed("xxx") { 50 atomic.AddInt64(&counter, 1) 51 time.Sleep(time.Millisecond) 52 atomic.AddInt64(&counter, -1) 53 p.Succeed("xxx") 54 } 55 time.Sleep(time.Millisecond) 56 } 57 wg.Done() 58 } 59 60 checker := func() { 61 for i := 0; i < 20; i++ { 62 assert(t, atomic.LoadInt64(&counter) <= 20) 63 time.Sleep(time.Millisecond) 64 } 65 wg.Done() 66 } 67 68 for i := 0; i < 10; i++ { 69 wg.Add(1) 70 go worker() 71 } 72 wg.Add(1) 73 go checker() 74 75 wg.Wait() 76 assert(t, counter == 0) 77 } 78 79 func BenchmarkPanelClosed_IsAllowed(b *testing.B) { 80 panel, err := NewPanel(nil, Options{}) 81 if err != nil { 82 b.Error(err) 83 } 84 key := "test" 85 b.ReportAllocs() 86 b.ResetTimer() 87 for i := 0; i < b.N; i++ { 88 panel.IsAllowed(key) 89 } 90 } 91 92 func BenchmarkPanelClosed_Succeed(b *testing.B) { 93 panel, err := NewPanel(nil, Options{}) 94 if err != nil { 95 b.Error(err) 96 } 97 key := "test" 98 b.ReportAllocs() 99 b.ResetTimer() 100 for i := 0; i < b.N; i++ { 101 panel.Succeed(key) 102 } 103 } 104 105 func BenchmarkPanelClosed_Fail(b *testing.B) { 106 panel, err := NewPanel(nil, Options{ 107 CoolingTimeout: time.Minute, 108 DetectTimeout: time.Minute, 109 ShouldTrip: testRateTripFuncFalse(1, 1), 110 }) 111 if err != nil { 112 b.Error(err) 113 } 114 key := "test" 115 b.ReportAllocs() 116 b.ResetTimer() 117 for i := 0; i < b.N; i++ { 118 panel.Fail(key) 119 } 120 } 121 122 func BenchmarkPanelClosed_Timeout(b *testing.B) { 123 panel, err := NewPanel(nil, Options{ 124 CoolingTimeout: time.Minute, 125 DetectTimeout: time.Minute, 126 ShouldTrip: testRateTripFuncFalse(1, 1), 127 }) 128 if err != nil { 129 b.Error(err) 130 } 131 key := "test" 132 b.ReportAllocs() 133 b.ResetTimer() 134 for i := 0; i < b.N; i++ { 135 panel.Timeout(key) 136 } 137 } 138 139 func BenchmarkPanelOpen_IsAllowed(b *testing.B) { 140 p, err := NewPanel(nil, Options{ 141 CoolingTimeout: time.Minute, 142 DetectTimeout: time.Minute, 143 ShouldTrip: testRateTripFuncFalse(1, 1), 144 }) 145 if err != nil { 146 b.Error(err) 147 } 148 key := "test" 149 p.(*panel).getBreaker(key).state = Open 150 b.ReportAllocs() 151 b.ResetTimer() 152 for i := 0; i < b.N; i++ { 153 p.IsAllowed(key) 154 } 155 } 156 157 func BenchmarkPanelOpen_Succeed(b *testing.B) { 158 p, err := NewPanel(nil, Options{ 159 CoolingTimeout: time.Minute, 160 DetectTimeout: time.Minute, 161 ShouldTrip: testRateTripFuncFalse(1, 1), 162 }) 163 if err != nil { 164 b.Error(err) 165 } 166 key := "test" 167 p.(*panel).getBreaker(key).state = Open 168 b.ReportAllocs() 169 b.ResetTimer() 170 for i := 0; i < b.N; i++ { 171 p.Succeed(key) 172 } 173 } 174 175 func BenchmarkPanelOpen_Fail(b *testing.B) { 176 p, err := NewPanel(nil, Options{ 177 CoolingTimeout: time.Minute, 178 DetectTimeout: time.Minute, 179 ShouldTrip: testRateTripFuncFalse(1, 1), 180 }) 181 if err != nil { 182 b.Error(err) 183 } 184 key := "test" 185 p.(*panel).getBreaker(key).state = Open 186 b.ReportAllocs() 187 b.ResetTimer() 188 for i := 0; i < b.N; i++ { 189 p.Fail(key) 190 } 191 } 192 193 func BenchmarkPanelOpen_Timeout(b *testing.B) { 194 p, err := NewPanel(nil, Options{ 195 CoolingTimeout: time.Minute, 196 DetectTimeout: time.Minute, 197 ShouldTrip: testRateTripFuncFalse(1, 1), 198 }) 199 if err != nil { 200 b.Error(err) 201 } 202 key := "test" 203 p.(*panel).getBreaker(key).state = Open 204 b.ReportAllocs() 205 b.ResetTimer() 206 for i := 0; i < b.N; i++ { 207 p.Timeout(key) 208 } 209 } 210 211 func BenchmarkPanelParallel_Succeed(b *testing.B) { 212 panel, err := NewPanel(nil, Options{}) 213 if err != nil { 214 b.Error(err) 215 } 216 key := "test" 217 key2 := "test2" 218 key3 := "test3" 219 b.ResetTimer() 220 b.RunParallel(func(pb *testing.PB) { 221 for pb.Next() { 222 panel.IsAllowed(key) 223 panel.IsAllowed(key2) 224 panel.IsAllowed(key3) 225 panel.Succeed(key) 226 panel.Succeed(key2) 227 panel.Succeed(key3) 228 } 229 }) 230 } 231 232 func BenchmarkPerPPanelParallel_Succeed(b *testing.B) { 233 panel, err := NewPanel(nil, Options{EnableShardP: true}) 234 if err != nil { 235 b.Error(err) 236 } 237 key := "test" 238 key2 := "test2" 239 key3 := "test3" 240 b.ResetTimer() 241 b.RunParallel(func(pb *testing.PB) { 242 for pb.Next() { 243 panel.IsAllowed(key) 244 panel.IsAllowed(key2) 245 panel.IsAllowed(key3) 246 panel.Succeed(key) 247 panel.Succeed(key2) 248 panel.Succeed(key3) 249 } 250 }) 251 } 252 253 func BenchmarkPanelOpenParallel_IsAllowed(b *testing.B) { 254 p, err := NewPanel(nil, Options{ 255 CoolingTimeout: time.Minute, 256 DetectTimeout: time.Minute, 257 ShouldTrip: testRateTripFuncFalse(1, 1), 258 }) 259 if err != nil { 260 b.Error(err) 261 } 262 key := "test" 263 key2 := "test2" 264 key3 := "test3" 265 p.(*panel).getBreaker(key).state = Open 266 p.(*panel).getBreaker(key2).state = Open 267 p.(*panel).getBreaker(key3).state = Open 268 b.ResetTimer() 269 b.RunParallel(func(pb *testing.PB) { 270 for pb.Next() { 271 p.IsAllowed(key) 272 p.IsAllowed(key2) 273 p.IsAllowed(key3) 274 } 275 }) 276 } 277 278 func BenchmarkPanelParallel2Cores_Succeed(b *testing.B) { 279 b.SetParallelism(2) 280 p, err := NewPanel(nil, Options{}) 281 if err != nil { 282 b.Error(err) 283 } 284 key := "test" 285 key2 := "test2" 286 key3 := "test3" 287 p.(*panel).getBreaker(key) 288 p.(*panel).getBreaker(key2) 289 p.(*panel).getBreaker(key3) 290 b.ResetTimer() 291 b.RunParallel(func(pb *testing.PB) { 292 for pb.Next() { 293 p.IsAllowed(key) 294 p.IsAllowed(key2) 295 p.IsAllowed(key3) 296 p.Succeed(key) 297 p.Succeed(key2) 298 p.Succeed(key3) 299 } 300 }) 301 } 302 303 func BenchmarkPerPPanelParallel2Cores_Succeed(b *testing.B) { 304 b.SetParallelism(2) 305 p, err := NewPanel(nil, Options{EnableShardP: true}) 306 if err != nil { 307 b.Error(err) 308 } 309 key := "test" 310 key2 := "test2" 311 key3 := "test3" 312 p.(*panel).getBreaker(key) 313 p.(*panel).getBreaker(key2) 314 p.(*panel).getBreaker(key3) 315 b.ResetTimer() 316 b.RunParallel(func(pb *testing.PB) { 317 for pb.Next() { 318 p.IsAllowed(key) 319 p.IsAllowed(key2) 320 p.IsAllowed(key3) 321 p.Succeed(key) 322 p.Succeed(key2) 323 p.Succeed(key3) 324 } 325 }) 326 } 327 328 func BenchmarkPanelOpenParallel2Cores_IsAllowed(b *testing.B) { 329 b.SetParallelism(2) 330 p, err := NewPanel(nil, Options{ 331 CoolingTimeout: time.Minute, 332 DetectTimeout: time.Minute, 333 ShouldTrip: testRateTripFuncFalse(1, 1), 334 }) 335 if err != nil { 336 b.Error(err) 337 } 338 key := "test" 339 key2 := "test2" 340 key3 := "test3" 341 p.(*panel).getBreaker(key).state = Open 342 p.(*panel).getBreaker(key2).state = Open 343 p.(*panel).getBreaker(key3).state = Open 344 b.ResetTimer() 345 b.RunParallel(func(pb *testing.PB) { 346 for pb.Next() { 347 p.IsAllowed(key) 348 p.IsAllowed(key2) 349 p.IsAllowed(key3) 350 } 351 }) 352 }