tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

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 };