(t *testing.T)
| 23 | ) |
| 24 | |
| 25 | func TestMultithreadedThrottling(t *testing.T) { |
| 26 | // Bucket with 100QPS and no burst |
| 27 | r := NewTokenBucketRateLimiter(100, 1) |
| 28 | |
| 29 | // channel to collect 100 tokens |
| 30 | taken := make(chan bool, 100) |
| 31 | |
| 32 | // Set up goroutines to hammer the throttler |
| 33 | startCh := make(chan bool) |
| 34 | endCh := make(chan bool) |
| 35 | for i := 0; i < 10; i++ { |
| 36 | go func() { |
| 37 | // wait for the starting signal |
| 38 | <-startCh |
| 39 | for { |
| 40 | // get a token |
| 41 | r.Accept() |
| 42 | select { |
| 43 | // try to add it to the taken channel |
| 44 | case taken <- true: |
| 45 | continue |
| 46 | // if taken is full, notify and return |
| 47 | default: |
| 48 | endCh <- true |
| 49 | return |
| 50 | } |
| 51 | } |
| 52 | }() |
| 53 | } |
| 54 | |
| 55 | // record wall time |
| 56 | startTime := time.Now() |
| 57 | // take the initial capacity so all tokens are the result of refill |
| 58 | r.Accept() |
| 59 | // start the thundering herd |
| 60 | close(startCh) |
| 61 | // wait for the first signal that we collected 100 tokens |
| 62 | <-endCh |
| 63 | // record wall time |
| 64 | endTime := time.Now() |
| 65 | |
| 66 | // tolerate a 1% clock change because these things happen |
| 67 | if duration := endTime.Sub(startTime); duration < (time.Second * 99 / 100) { |
| 68 | // We shouldn't be able to get 100 tokens out of the bucket in less than 1 second of wall clock time, no matter what |
| 69 | t.Errorf("Expected it to take at least 1 second to get 100 tokens, took %v", duration) |
| 70 | } else { |
| 71 | t.Logf("Took %v to get 100 tokens", duration) |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | func TestBasicThrottle(t *testing.T) { |
| 76 | r := NewTokenBucketRateLimiter(1, 3) |
nothing calls this directly
no test coverage detected