tokenbucket_test.go 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. package tokenbucket_test
  2. import (
  3. "github.com/ChimeraCoder/tokenbucket"
  4. "testing"
  5. "time"
  6. )
  7. func Example_BucketUse() {
  8. // Allow a new action every 5 seconds, with a maximum of 3 "in the bank"
  9. bucket := tokenbucket.NewBucket(5*time.Second, 3)
  10. // To perform a regulated action, we must spend a token
  11. // RegulatedAction will not be performed until the bucket contains enough tokens
  12. <-bucket.SpendToken(1)
  13. RegulatedAction()
  14. }
  15. // RegulatedAction represents some function that is rate-limited, monitored,
  16. // or otherwise regulated
  17. func RegulatedAction() {
  18. // Some expensive action goes on here
  19. }
  20. // Test that a bucket that is full does not block execution
  21. func Test_BucketBuffering(t *testing.T) {
  22. // Create a bucket with capacity 3, that adds tokens every 4 seconds
  23. const RATE = 4 * time.Second
  24. const CAPACITY = 3
  25. const ERROR = 500 * time.Millisecond
  26. b := tokenbucket.NewBucket(RATE, CAPACITY)
  27. // Allow the bucket enough time to fill to capacity
  28. time.Sleep(CAPACITY * RATE)
  29. // Check that we can empty the bucket without wasting any time
  30. before := time.Now()
  31. <-b.SpendToken(1)
  32. <-b.SpendToken(1)
  33. <-b.SpendToken(1)
  34. after := time.Now()
  35. if diff := after.Sub(before); diff > RATE {
  36. t.Errorf("Waited %d seconds, though this should have been nearly instantaneous", diff)
  37. }
  38. }
  39. // Test that a bucket that is empty blocks execution for the correct amount of time
  40. func Test_BucketCreation(t *testing.T) {
  41. // Create a bucket with capacity 3, that adds tokens every 4 seconds
  42. const RATE = 4 * time.Second
  43. const CAPACITY = 3
  44. const ERROR = 500 * time.Millisecond
  45. const EXPECTED_DURATION = RATE * CAPACITY
  46. b := tokenbucket.NewBucket(RATE, CAPACITY)
  47. // Ensure that the bucket is empty
  48. <-b.SpendToken(1)
  49. <-b.SpendToken(1)
  50. <-b.SpendToken(1)
  51. <-b.SpendToken(1)
  52. // Spending three times on an empty bucket should take 12 seconds
  53. // (Take the average across three, due to imprecision/scheduling)
  54. before := time.Now()
  55. <-b.SpendToken(1)
  56. <-b.SpendToken(1)
  57. <-b.SpendToken(1)
  58. after := time.Now()
  59. lower := EXPECTED_DURATION - ERROR
  60. upper := EXPECTED_DURATION + ERROR
  61. if diff := after.Sub(before); diff < lower || diff > upper {
  62. t.Errorf("Waited %s seconds, though really should have waited between %s and %s", diff.String(), lower.String(), upper.String())
  63. }
  64. }