1 /* Copyright (c) 2018, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
6 * \brief tests for bandwidth management / token bucket functions
9 #define TOKEN_BUCKET_PRIVATE
11 #include "core/or/or.h"
12 #include "test/test.h"
14 #include "lib/evloop/token_bucket.h"
16 // an imaginary time, in timestamp units. Chosen so it will roll over.
17 static const uint32_t START_TS
= UINT32_MAX
-10;
18 static const int32_t KB
= 1024;
19 static const uint32_t GB
= (UINT64_C(1) << 30);
22 test_bwmgt_token_buf_init(void *arg
)
27 token_bucket_rw_init(&b
, 16*KB
, 64*KB
, START_TS
);
29 tt_uint_op(b
.cfg
.burst
, OP_EQ
, 64*KB
);
30 // Rate is correct, within 1 percent.
32 uint32_t ticks_per_sec
=
33 (uint32_t) monotime_msec_to_approx_coarse_stamp_units(1000);
34 uint32_t rate_per_sec
= (b
.cfg
.rate
* ticks_per_sec
/ TICKS_PER_STEP
);
36 tt_uint_op(rate_per_sec
, OP_GT
, 16*KB
-160);
37 tt_uint_op(rate_per_sec
, OP_LT
, 16*KB
+160);
39 // Bucket starts out full:
40 tt_uint_op(b
.last_refilled_at_timestamp
, OP_EQ
, START_TS
);
41 tt_int_op(b
.read_bucket
.bucket
, OP_EQ
, 64*KB
);
48 test_bwmgt_token_buf_adjust(void *arg
)
53 token_bucket_rw_init(&b
, 16*KB
, 64*KB
, START_TS
);
55 uint32_t rate_orig
= b
.cfg
.rate
;
57 token_bucket_rw_adjust(&b
, 16*KB
, 128*KB
);
58 tt_uint_op(b
.cfg
.rate
, OP_EQ
, rate_orig
);
59 tt_uint_op(b
.read_bucket
.bucket
, OP_EQ
, 64*KB
);
60 tt_uint_op(b
.cfg
.burst
, OP_EQ
, 128*KB
);
62 // Decreasing burst but staying above bucket
63 token_bucket_rw_adjust(&b
, 16*KB
, 96*KB
);
64 tt_uint_op(b
.cfg
.rate
, OP_EQ
, rate_orig
);
65 tt_uint_op(b
.read_bucket
.bucket
, OP_EQ
, 64*KB
);
66 tt_uint_op(b
.cfg
.burst
, OP_EQ
, 96*KB
);
68 // Decreasing burst below bucket,
69 token_bucket_rw_adjust(&b
, 16*KB
, 48*KB
);
70 tt_uint_op(b
.cfg
.rate
, OP_EQ
, rate_orig
);
71 tt_uint_op(b
.read_bucket
.bucket
, OP_EQ
, 48*KB
);
72 tt_uint_op(b
.cfg
.burst
, OP_EQ
, 48*KB
);
75 token_bucket_rw_adjust(&b
, 32*KB
, 48*KB
);
76 tt_uint_op(b
.cfg
.rate
, OP_GE
, rate_orig
*2 - 10);
77 tt_uint_op(b
.cfg
.rate
, OP_LE
, rate_orig
*2 + 10);
78 tt_uint_op(b
.read_bucket
.bucket
, OP_EQ
, 48*KB
);
79 tt_uint_op(b
.cfg
.burst
, OP_EQ
, 48*KB
);
86 test_bwmgt_token_buf_dec(void *arg
)
90 token_bucket_rw_init(&b
, 16*KB
, 64*KB
, START_TS
);
93 tt_int_op(0, OP_EQ
, token_bucket_rw_dec_read(&b
, KB
));
94 tt_int_op(b
.read_bucket
.bucket
, OP_EQ
, 63*KB
);
96 // Full to almost-not-full
97 tt_int_op(0, OP_EQ
, token_bucket_rw_dec_read(&b
, 63*KB
- 1));
98 tt_int_op(b
.read_bucket
.bucket
, OP_EQ
, 1);
100 // almost-not-full to empty.
101 tt_int_op(1, OP_EQ
, token_bucket_rw_dec_read(&b
, 1));
102 tt_int_op(b
.read_bucket
.bucket
, OP_EQ
, 0);
104 // reset bucket, try full-to-empty
105 token_bucket_rw_init(&b
, 16*KB
, 64*KB
, START_TS
);
106 tt_int_op(1, OP_EQ
, token_bucket_rw_dec_read(&b
, 64*KB
));
107 tt_int_op(b
.read_bucket
.bucket
, OP_EQ
, 0);
109 // reset bucket, try underflow.
110 token_bucket_rw_init(&b
, 16*KB
, 64*KB
, START_TS
);
111 tt_int_op(1, OP_EQ
, token_bucket_rw_dec_read(&b
, 64*KB
+ 1));
112 tt_int_op(b
.read_bucket
.bucket
, OP_EQ
, -1);
114 // A second underflow does not make the bucket empty.
115 tt_int_op(0, OP_EQ
, token_bucket_rw_dec_read(&b
, 1000));
116 tt_int_op(b
.read_bucket
.bucket
, OP_EQ
, -1001);
123 test_bwmgt_token_buf_refill(void *arg
)
127 const uint32_t BW_SEC
=
128 (uint32_t)monotime_msec_to_approx_coarse_stamp_units(1000);
129 token_bucket_rw_init(&b
, 16*KB
, 64*KB
, START_TS
);
131 /* Make the buffer much emptier, then let one second elapse. */
132 token_bucket_rw_dec_read(&b
, 48*KB
);
133 tt_int_op(b
.read_bucket
.bucket
, OP_EQ
, 16*KB
);
134 tt_int_op(0, OP_EQ
, token_bucket_rw_refill(&b
, START_TS
+ BW_SEC
));
135 tt_int_op(b
.read_bucket
.bucket
, OP_GT
, 32*KB
- 300);
136 tt_int_op(b
.read_bucket
.bucket
, OP_LT
, 32*KB
+ 300);
138 /* Another half second. */
139 tt_int_op(0, OP_EQ
, token_bucket_rw_refill(&b
, START_TS
+ BW_SEC
*3/2));
140 tt_int_op(b
.read_bucket
.bucket
, OP_GT
, 40*KB
- 400);
141 tt_int_op(b
.read_bucket
.bucket
, OP_LT
, 40*KB
+ 400);
142 tt_uint_op(b
.last_refilled_at_timestamp
, OP_EQ
, START_TS
+ BW_SEC
*3/2);
144 /* No time: nothing happens. */
146 const uint32_t bucket_orig
= b
.read_bucket
.bucket
;
147 tt_int_op(0, OP_EQ
, token_bucket_rw_refill(&b
, START_TS
+ BW_SEC
*3/2));
148 tt_int_op(b
.read_bucket
.bucket
, OP_EQ
, bucket_orig
);
151 /* Another 30 seconds: fill the bucket. */
152 tt_int_op(0, OP_EQ
, token_bucket_rw_refill(&b
,
153 START_TS
+ BW_SEC
*3/2 + BW_SEC
*30));
154 tt_int_op(b
.read_bucket
.bucket
, OP_EQ
, b
.cfg
.burst
);
155 tt_uint_op(b
.last_refilled_at_timestamp
, OP_EQ
,
156 START_TS
+ BW_SEC
*3/2 + BW_SEC
*30);
158 /* Another 30 seconds: nothing happens. */
159 tt_int_op(0, OP_EQ
, token_bucket_rw_refill(&b
,
160 START_TS
+ BW_SEC
*3/2 + BW_SEC
*60));
161 tt_int_op(b
.read_bucket
.bucket
, OP_EQ
, b
.cfg
.burst
);
162 tt_uint_op(b
.last_refilled_at_timestamp
, OP_EQ
,
163 START_TS
+ BW_SEC
*3/2 + BW_SEC
*60);
165 /* Empty the bucket, let two seconds pass, and make sure that a refill is
167 tt_int_op(1, OP_EQ
, token_bucket_rw_dec_read(&b
, b
.cfg
.burst
));
168 tt_int_op(0, OP_EQ
, b
.read_bucket
.bucket
);
169 tt_int_op(1, OP_EQ
, token_bucket_rw_refill(&b
,
170 START_TS
+ BW_SEC
*3/2 + BW_SEC
*61));
171 tt_int_op(0, OP_EQ
, token_bucket_rw_refill(&b
,
172 START_TS
+ BW_SEC
*3/2 + BW_SEC
*62));
173 tt_int_op(b
.read_bucket
.bucket
, OP_GT
, 32*KB
-400);
174 tt_int_op(b
.read_bucket
.bucket
, OP_LT
, 32*KB
+400);
176 /* Underflow the bucket, make sure we detect when it has tokens again. */
178 token_bucket_rw_dec_read(&b
, b
.read_bucket
.bucket
+16*KB
));
179 tt_int_op(-16*KB
, OP_EQ
, b
.read_bucket
.bucket
);
180 // half a second passes...
181 tt_int_op(0, OP_EQ
, token_bucket_rw_refill(&b
, START_TS
+ BW_SEC
*64));
182 tt_int_op(b
.read_bucket
.bucket
, OP_GT
, -8*KB
-300);
183 tt_int_op(b
.read_bucket
.bucket
, OP_LT
, -8*KB
+300);
185 tt_int_op(1, OP_EQ
, token_bucket_rw_refill(&b
, START_TS
+ BW_SEC
*65));
186 tt_int_op(b
.read_bucket
.bucket
, OP_GT
, 8*KB
-400);
187 tt_int_op(b
.read_bucket
.bucket
, OP_LT
, 8*KB
+400);
189 // We step a second backwards, and nothing happens.
190 tt_int_op(0, OP_EQ
, token_bucket_rw_refill(&b
, START_TS
+ BW_SEC
*64));
191 tt_int_op(b
.read_bucket
.bucket
, OP_GT
, 8*KB
-400);
192 tt_int_op(b
.read_bucket
.bucket
, OP_LT
, 8*KB
+400);
194 // A ridiculous amount of time passes.
195 tt_int_op(0, OP_EQ
, token_bucket_rw_refill(&b
, INT32_MAX
));
196 tt_int_op(b
.read_bucket
.bucket
, OP_EQ
, b
.cfg
.burst
);
202 /* Test some helper functions we use within the token bucket interface. */
204 test_bwmgt_token_buf_helpers(void *arg
)
210 /* The returned value will be OS specific but in any case, it should be
211 * greater than 1 since we are passing 1GB/sec rate. */
212 ret
= rate_per_sec_to_rate_per_step(1 * GB
);
213 tt_u64_op(ret
, OP_GT
, 1);
215 /* We default to 1 in case rate is 0. */
216 ret
= rate_per_sec_to_rate_per_step(0);
217 tt_u64_op(ret
, OP_EQ
, 1);
223 #define BWMGT(name) \
224 { #name, test_bwmgt_ ## name , 0, NULL, NULL }
226 struct testcase_t bwmgt_tests
[] = {
227 BWMGT(token_buf_init
),
228 BWMGT(token_buf_adjust
),
229 BWMGT(token_buf_dec
),
230 BWMGT(token_buf_refill
),
231 BWMGT(token_buf_helpers
),