github.com/cavaliergopher/grab/v3@v3.0.1/rate_limiter_test.go (about) 1 package grab 2 3 import ( 4 "context" 5 "log" 6 "os" 7 "testing" 8 "time" 9 10 "github.com/cavaliergopher/grab/v3/pkg/grabtest" 11 ) 12 13 // testRateLimiter is a naive rate limiter that limits throughput to r tokens 14 // per second. The total number of tokens issued is tracked as n. 15 type testRateLimiter struct { 16 r, n int 17 } 18 19 func NewLimiter(r int) RateLimiter { 20 return &testRateLimiter{r: r} 21 } 22 23 func (c *testRateLimiter) WaitN(ctx context.Context, n int) (err error) { 24 c.n += n 25 time.Sleep( 26 time.Duration(1.00 / float64(c.r) * float64(n) * float64(time.Second))) 27 return 28 } 29 30 func TestRateLimiter(t *testing.T) { 31 // download a 128 byte file, 8 bytes at a time, with a naive 512bps limiter 32 // should take > 250ms 33 filesize := 128 34 filename := ".testRateLimiter" 35 defer os.Remove(filename) 36 37 grabtest.WithTestServer(t, func(url string) { 38 // limit to 512bps 39 lim := &testRateLimiter{r: 512} 40 req := mustNewRequest(filename, url) 41 42 // ensure multiple trips to the rate limiter by downloading 8 bytes at a time 43 req.BufferSize = 8 44 req.RateLimiter = lim 45 46 resp := mustDo(req) 47 testComplete(t, resp) 48 if lim.n != filesize { 49 t.Errorf("expected %d bytes to pass through limiter, got %d", filesize, lim.n) 50 } 51 if resp.Duration().Seconds() < 0.25 { 52 // BUG: this test can pass if the transfer was slow for unrelated reasons 53 t.Errorf("expected transfer to take >250ms, took %v", resp.Duration()) 54 } 55 }, grabtest.ContentLength(filesize)) 56 } 57 58 func ExampleRateLimiter() { 59 req, _ := NewRequest("", "http://www.golang-book.com/public/pdf/gobook.pdf") 60 61 // Attach a 1Mbps rate limiter, like the token bucket implementation from 62 // golang.org/x/time/rate. 63 req.RateLimiter = NewLimiter(1048576) 64 65 resp := DefaultClient.Do(req) 66 if err := resp.Err(); err != nil { 67 log.Fatal(err) 68 } 69 }