Files
rpcx/client/circuit_breaker_test.go
liaotonglang 5ea95294ae fix race on cb.lastFailureTime
struct ConsecCircuitBreaker{} cannot pass the race test below:
	go test ./client -race -run TestCircuitBreakerRace$

Split compond type value lastFailureTime (time.Time) to second and nano,
then we can use atomic.
2022-01-25 11:26:40 +08:00

76 lines
1.4 KiB
Go

package client
import (
"errors"
"math/rand"
"testing"
"time"
)
func TestConsecCircuitBreaker(t *testing.T) {
count := -1
fn := func() error {
count++
if count >= 5 && count < 10 {
return nil
}
return errors.New("test error")
}
cb := NewConsecCircuitBreaker(5, 100*time.Millisecond)
for i := 0; i < 25; i++ {
err := cb.Call(fn, 200*time.Millisecond)
switch {
case i < 5:
if err.Error() != "test error" {
t.Fatalf("expect %v, got %v", "test error", err)
}
case i >= 5 && i < 10:
if err != ErrBreakerOpen {
t.Fatalf("expect %v, got %v", ErrBreakerOpen, err)
}
case i >= 10 && i < 15:
if err != nil {
t.Fatalf("expect success, got %v", err)
}
case i >= 15 && i < 20:
if err.Error() != "test error" {
t.Fatalf("expect %v, got %v", "test error", err)
}
case i >= 20 && i < 25:
if err != ErrBreakerOpen {
t.Fatalf("expect %v, got %v", ErrBreakerOpen, err)
}
}
if i == 9 { // expired
time.Sleep(150 * time.Millisecond)
}
}
}
func TestCircuitBreakerRace(t *testing.T) {
cb := NewConsecCircuitBreaker(2, 50*time.Millisecond)
routines := 100
loop := 100000
fn := func() error {
if rand.Intn(2) == 1 {
return nil
}
return errors.New("test error")
}
for r := 0; r < routines; r++ {
go func() {
for i := 0; i < loop; i++ {
cb.Call(fn, 100*time.Millisecond)
}
}()
}
}