test_token_bucket.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /* Copyright (c) 2018-2019, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file test_bwmgt.c
  5. * \brief tests for bandwidth management / token bucket functions
  6. */
  7. #define TOKEN_BUCKET_PRIVATE
  8. #include "core/or/or.h"
  9. #include "test/test.h"
  10. #include "lib/evloop/token_bucket.h"
  11. // an imaginary time, in timestamp units. Chosen so it will roll over.
  12. static const uint32_t START_TS = UINT32_MAX - 1000;
  13. static const uint32_t RATE = 10;
  14. static const uint32_t BURST = 50;
  15. static void
  16. test_token_bucket_ctr_init(void *arg)
  17. {
  18. (void) arg;
  19. token_bucket_ctr_t tb;
  20. token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
  21. tt_uint_op(tb.cfg.rate, OP_EQ, RATE);
  22. tt_uint_op(tb.cfg.burst, OP_EQ, BURST);
  23. tt_uint_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS);
  24. tt_int_op(tb.counter.bucket, OP_EQ, BURST);
  25. done:
  26. ;
  27. }
  28. static void
  29. test_token_bucket_ctr_adjust(void *arg)
  30. {
  31. (void) arg;
  32. token_bucket_ctr_t tb;
  33. token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
  34. /* Increase burst. */
  35. token_bucket_ctr_adjust(&tb, RATE, BURST * 2);
  36. tt_uint_op(tb.cfg.rate, OP_EQ, RATE);
  37. tt_uint_op(tb.counter.bucket, OP_EQ, BURST);
  38. tt_uint_op(tb.cfg.burst, OP_EQ, BURST * 2);
  39. /* Decrease burst but still above bucket value. */
  40. token_bucket_ctr_adjust(&tb, RATE, BURST + 10);
  41. tt_uint_op(tb.cfg.rate, OP_EQ, RATE);
  42. tt_uint_op(tb.counter.bucket, OP_EQ, BURST);
  43. tt_uint_op(tb.cfg.burst, OP_EQ, BURST + 10);
  44. /* Decrease burst below bucket value. */
  45. token_bucket_ctr_adjust(&tb, RATE, BURST - 1);
  46. tt_uint_op(tb.cfg.rate, OP_EQ, RATE);
  47. tt_uint_op(tb.counter.bucket, OP_EQ, BURST - 1);
  48. tt_uint_op(tb.cfg.burst, OP_EQ, BURST - 1);
  49. /* Change rate. */
  50. token_bucket_ctr_adjust(&tb, RATE * 2, BURST);
  51. tt_uint_op(tb.cfg.rate, OP_EQ, RATE * 2);
  52. tt_uint_op(tb.counter.bucket, OP_EQ, BURST - 1);
  53. tt_uint_op(tb.cfg.burst, OP_EQ, BURST);
  54. done:
  55. ;
  56. }
  57. static void
  58. test_token_bucket_ctr_dec(void *arg)
  59. {
  60. (void) arg;
  61. token_bucket_ctr_t tb;
  62. token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
  63. /* Simple decrement by one. */
  64. tt_uint_op(0, OP_EQ, token_bucket_ctr_dec(&tb, 1));
  65. tt_uint_op(tb.counter.bucket, OP_EQ, BURST - 1);
  66. /* Down to 0. Becomes empty. */
  67. tt_uint_op(true, OP_EQ, token_bucket_ctr_dec(&tb, BURST - 1));
  68. tt_uint_op(tb.counter.bucket, OP_EQ, 0);
  69. /* Reset and try to underflow. */
  70. token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
  71. tt_uint_op(true, OP_EQ, token_bucket_ctr_dec(&tb, BURST + 1));
  72. tt_int_op(tb.counter.bucket, OP_EQ, -1);
  73. /* Keep underflowing shouldn't flag the bucket as empty. */
  74. tt_uint_op(false, OP_EQ, token_bucket_ctr_dec(&tb, BURST));
  75. tt_int_op(tb.counter.bucket, OP_EQ, - (int32_t) (BURST + 1));
  76. done:
  77. ;
  78. }
  79. static void
  80. test_token_bucket_ctr_refill(void *arg)
  81. {
  82. (void) arg;
  83. token_bucket_ctr_t tb;
  84. token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
  85. /* Reduce of half the bucket and let a single second go before refill. */
  86. token_bucket_ctr_dec(&tb, BURST / 2);
  87. tt_int_op(tb.counter.bucket, OP_EQ, BURST / 2);
  88. token_bucket_ctr_refill(&tb, START_TS + 1);
  89. tt_int_op(tb.counter.bucket, OP_EQ, (BURST / 2) + RATE);
  90. tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 1);
  91. /* No time change, nothing should move. */
  92. token_bucket_ctr_refill(&tb, START_TS + 1);
  93. tt_int_op(tb.counter.bucket, OP_EQ, (BURST / 2) + RATE);
  94. tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 1);
  95. /* Add 99 seconds, bucket should be back to a full BURST. */
  96. token_bucket_ctr_refill(&tb, START_TS + 99);
  97. tt_int_op(tb.counter.bucket, OP_EQ, BURST);
  98. tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 99);
  99. /* Empty bucket at once. */
  100. token_bucket_ctr_dec(&tb, BURST);
  101. tt_int_op(tb.counter.bucket, OP_EQ, 0);
  102. /* On second passes. */
  103. token_bucket_ctr_refill(&tb, START_TS + 100);
  104. tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 100);
  105. tt_int_op(tb.counter.bucket, OP_EQ, RATE);
  106. /* A second second passes. */
  107. token_bucket_ctr_refill(&tb, START_TS + 101);
  108. tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 101);
  109. tt_int_op(tb.counter.bucket, OP_EQ, RATE * 2);
  110. done:
  111. ;
  112. }
  113. #define TOKEN_BUCKET(name) \
  114. { #name, test_token_bucket_ ## name , 0, NULL, NULL }
  115. struct testcase_t token_bucket_tests[] = {
  116. TOKEN_BUCKET(ctr_init),
  117. TOKEN_BUCKET(ctr_adjust),
  118. TOKEN_BUCKET(ctr_dec),
  119. TOKEN_BUCKET(ctr_refill),
  120. END_OF_TESTCASES
  121. };