Line data Source code
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 1 : test_token_bucket_ctr_init(void *arg)
23 : {
24 1 : (void) arg;
25 1 : token_bucket_ctr_t tb;
26 :
27 1 : token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
28 1 : tt_uint_op(tb.cfg.rate, OP_EQ, RATE);
29 1 : tt_uint_op(tb.cfg.burst, OP_EQ, BURST);
30 1 : tt_uint_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS);
31 1 : tt_int_op(tb.counter.bucket, OP_EQ, BURST);
32 :
33 1 : done:
34 1 : ;
35 1 : }
36 :
37 : static void
38 1 : test_token_bucket_ctr_adjust(void *arg)
39 : {
40 1 : (void) arg;
41 1 : token_bucket_ctr_t tb;
42 :
43 1 : token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
44 :
45 : /* Increase burst. */
46 1 : token_bucket_ctr_adjust(&tb, RATE, BURST * 2);
47 1 : tt_uint_op(tb.cfg.rate, OP_EQ, RATE);
48 1 : tt_uint_op(tb.counter.bucket, OP_EQ, BURST);
49 1 : tt_uint_op(tb.cfg.burst, OP_EQ, BURST * 2);
50 :
51 : /* Decrease burst but still above bucket value. */
52 1 : token_bucket_ctr_adjust(&tb, RATE, BURST + 10);
53 1 : tt_uint_op(tb.cfg.rate, OP_EQ, RATE);
54 1 : tt_uint_op(tb.counter.bucket, OP_EQ, BURST);
55 1 : tt_uint_op(tb.cfg.burst, OP_EQ, BURST + 10);
56 :
57 : /* Decrease burst below bucket value. */
58 1 : token_bucket_ctr_adjust(&tb, RATE, BURST - 1);
59 1 : tt_uint_op(tb.cfg.rate, OP_EQ, RATE);
60 1 : tt_uint_op(tb.counter.bucket, OP_EQ, BURST - 1);
61 1 : tt_uint_op(tb.cfg.burst, OP_EQ, BURST - 1);
62 :
63 : /* Change rate. */
64 1 : token_bucket_ctr_adjust(&tb, RATE * 2, BURST);
65 1 : tt_uint_op(tb.cfg.rate, OP_EQ, RATE * 2);
66 1 : tt_uint_op(tb.counter.bucket, OP_EQ, BURST - 1);
67 1 : tt_uint_op(tb.cfg.burst, OP_EQ, BURST);
68 :
69 1 : done:
70 1 : ;
71 1 : }
72 :
73 : static void
74 1 : test_token_bucket_ctr_dec(void *arg)
75 : {
76 1 : (void) arg;
77 1 : token_bucket_ctr_t tb;
78 :
79 1 : token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
80 :
81 : /* Simple decrement by one. */
82 1 : tt_uint_op(0, OP_EQ, token_bucket_ctr_dec(&tb, 1));
83 1 : tt_uint_op(tb.counter.bucket, OP_EQ, BURST - 1);
84 :
85 : /* Down to 0. Becomes empty. */
86 1 : tt_uint_op(true, OP_EQ, token_bucket_ctr_dec(&tb, BURST - 1));
87 1 : tt_uint_op(tb.counter.bucket, OP_EQ, 0);
88 :
89 : /* Reset and try to underflow. */
90 1 : token_bucket_ctr_init(&tb, RATE, BURST, START_TS);
91 1 : tt_uint_op(true, OP_EQ, token_bucket_ctr_dec(&tb, BURST + 1));
92 1 : tt_int_op(tb.counter.bucket, OP_EQ, -1);
93 :
94 : /* Keep underflowing shouldn't flag the bucket as empty. */
95 1 : tt_uint_op(false, OP_EQ, token_bucket_ctr_dec(&tb, BURST));
96 1 : tt_int_op(tb.counter.bucket, OP_EQ, - (int32_t) (BURST + 1));
97 :
98 1 : done:
99 1 : ;
100 1 : }
101 :
102 : static void
103 1 : test_token_bucket_ctr_refill(void *arg)
104 : {
105 1 : (void) arg;
106 1 : token_bucket_ctr_t tb;
107 :
108 1 : 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 1 : token_bucket_ctr_dec(&tb, BURST / 2);
112 1 : tt_int_op(tb.counter.bucket, OP_EQ, BURST / 2);
113 1 : token_bucket_ctr_refill(&tb, START_TS + 1);
114 1 : tt_int_op(tb.counter.bucket, OP_EQ, (BURST / 2) + RATE);
115 1 : tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 1);
116 :
117 : /* No time change, nothing should move. */
118 1 : token_bucket_ctr_refill(&tb, START_TS + 1);
119 1 : tt_int_op(tb.counter.bucket, OP_EQ, (BURST / 2) + RATE);
120 1 : 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 1 : token_bucket_ctr_refill(&tb, START_TS + 99);
124 1 : tt_int_op(tb.counter.bucket, OP_EQ, BURST);
125 1 : tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 99);
126 :
127 : /* Empty bucket at once. */
128 1 : token_bucket_ctr_dec(&tb, BURST);
129 1 : tt_int_op(tb.counter.bucket, OP_EQ, 0);
130 : /* On second passes. */
131 1 : token_bucket_ctr_refill(&tb, START_TS + 100);
132 1 : tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 100);
133 1 : tt_int_op(tb.counter.bucket, OP_EQ, RATE);
134 : /* A second second passes. */
135 1 : token_bucket_ctr_refill(&tb, START_TS + 101);
136 1 : tt_int_op(tb.last_refilled_at_timestamp, OP_EQ, START_TS + 101);
137 1 : tt_int_op(tb.counter.bucket, OP_EQ, RATE * 2);
138 :
139 1 : done:
140 1 : ;
141 1 : }
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 : };
|