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