Home | History | Annotate | Download | only in backoff
      1 /*
      2  *
      3  * Copyright 2016 gRPC authors.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  *
     17  */
     18 
     19 #include "src/core/lib/backoff/backoff.h"
     20 
     21 #include <algorithm>
     22 
     23 #include <grpc/support/log.h>
     24 
     25 #include <gtest/gtest.h>
     26 #include "test/core/util/test_config.h"
     27 
     28 namespace grpc {
     29 namespace testing {
     30 namespace {
     31 
     32 using grpc_core::BackOff;
     33 
     34 TEST(BackOffTest, ConstantBackOff) {
     35   const grpc_millis initial_backoff = 200;
     36   const double multiplier = 1.0;
     37   const double jitter = 0.0;
     38   const grpc_millis max_backoff = 1000;
     39   grpc_core::ExecCtx exec_ctx;
     40   BackOff::Options options;
     41   options.set_initial_backoff(initial_backoff)
     42       .set_multiplier(multiplier)
     43       .set_jitter(jitter)
     44       .set_max_backoff(max_backoff);
     45   BackOff backoff(options);
     46 
     47   grpc_millis next_attempt_start_time = backoff.NextAttemptTime();
     48   EXPECT_EQ(next_attempt_start_time - grpc_core::ExecCtx::Get()->Now(),
     49             initial_backoff);
     50   for (int i = 0; i < 10000; i++) {
     51     next_attempt_start_time = backoff.NextAttemptTime();
     52     EXPECT_EQ(next_attempt_start_time - grpc_core::ExecCtx::Get()->Now(),
     53               initial_backoff);
     54   }
     55 }
     56 
     57 TEST(BackOffTest, MinConnect) {
     58   const grpc_millis initial_backoff = 100;
     59   const double multiplier = 1.0;
     60   const double jitter = 0.0;
     61   const grpc_millis max_backoff = 1000;
     62   grpc_core::ExecCtx exec_ctx;
     63   BackOff::Options options;
     64   options.set_initial_backoff(initial_backoff)
     65       .set_multiplier(multiplier)
     66       .set_jitter(jitter)
     67       .set_max_backoff(max_backoff);
     68   BackOff backoff(options);
     69   grpc_millis next = backoff.NextAttemptTime();
     70   EXPECT_EQ(next - grpc_core::ExecCtx::Get()->Now(), initial_backoff);
     71 }
     72 
     73 TEST(BackOffTest, NoJitterBackOff) {
     74   const grpc_millis initial_backoff = 2;
     75   const double multiplier = 2.0;
     76   const double jitter = 0.0;
     77   const grpc_millis max_backoff = 513;
     78   BackOff::Options options;
     79   options.set_initial_backoff(initial_backoff)
     80       .set_multiplier(multiplier)
     81       .set_jitter(jitter)
     82       .set_max_backoff(max_backoff);
     83   BackOff backoff(options);
     84   // x_1 = 2
     85   // x_n = 2**i + x_{i-1} ( = 2**(n+1) - 2 )
     86   grpc_core::ExecCtx exec_ctx;
     87   grpc_core::ExecCtx::Get()->TestOnlySetNow(0);
     88   grpc_millis next = backoff.NextAttemptTime();
     89   EXPECT_EQ(next, 2);
     90   grpc_core::ExecCtx::Get()->TestOnlySetNow(next);
     91   next = backoff.NextAttemptTime();
     92   EXPECT_EQ(next, 6);
     93   grpc_core::ExecCtx::Get()->TestOnlySetNow(next);
     94   next = backoff.NextAttemptTime();
     95   EXPECT_EQ(next, 14);
     96   grpc_core::ExecCtx::Get()->TestOnlySetNow(next);
     97   next = backoff.NextAttemptTime();
     98   EXPECT_EQ(next, 30);
     99   grpc_core::ExecCtx::Get()->TestOnlySetNow(next);
    100   next = backoff.NextAttemptTime();
    101   EXPECT_EQ(next, 62);
    102   grpc_core::ExecCtx::Get()->TestOnlySetNow(next);
    103   next = backoff.NextAttemptTime();
    104   EXPECT_EQ(next, 126);
    105   grpc_core::ExecCtx::Get()->TestOnlySetNow(next);
    106   next = backoff.NextAttemptTime();
    107   EXPECT_EQ(next, 254);
    108   grpc_core::ExecCtx::Get()->TestOnlySetNow(next);
    109   next = backoff.NextAttemptTime();
    110   EXPECT_EQ(next, 510);
    111   grpc_core::ExecCtx::Get()->TestOnlySetNow(next);
    112   next = backoff.NextAttemptTime();
    113   EXPECT_EQ(next, 1022);
    114   grpc_core::ExecCtx::Get()->TestOnlySetNow(next);
    115   next = backoff.NextAttemptTime();
    116   // Hit the maximum timeout. From this point onwards, retries will increase
    117   // only by max timeout.
    118   EXPECT_EQ(next, 1535);
    119   grpc_core::ExecCtx::Get()->TestOnlySetNow(next);
    120   next = backoff.NextAttemptTime();
    121   EXPECT_EQ(next, 2048);
    122   grpc_core::ExecCtx::Get()->TestOnlySetNow(next);
    123   next = backoff.NextAttemptTime();
    124   EXPECT_EQ(next, 2561);
    125 }
    126 
    127 TEST(BackOffTest, JitterBackOff) {
    128   const grpc_millis initial_backoff = 500;
    129   grpc_millis current_backoff = initial_backoff;
    130   const grpc_millis max_backoff = 1000;
    131   const double multiplier = 1.0;
    132   const double jitter = 0.1;
    133   BackOff::Options options;
    134   options.set_initial_backoff(initial_backoff)
    135       .set_multiplier(multiplier)
    136       .set_jitter(jitter)
    137       .set_max_backoff(max_backoff);
    138   BackOff backoff(options);
    139 
    140   backoff.SetRandomSeed(0);  // force consistent PRNG
    141 
    142   grpc_core::ExecCtx exec_ctx;
    143   grpc_millis next = backoff.NextAttemptTime();
    144   EXPECT_EQ(next - grpc_core::ExecCtx::Get()->Now(), initial_backoff);
    145 
    146   grpc_millis expected_next_lower_bound = static_cast<grpc_millis>(
    147       static_cast<double>(current_backoff) * (1 - jitter));
    148   grpc_millis expected_next_upper_bound = static_cast<grpc_millis>(
    149       static_cast<double>(current_backoff) * (1 + jitter));
    150 
    151   for (int i = 0; i < 10000; i++) {
    152     next = backoff.NextAttemptTime();
    153     // next-now must be within (jitter*100)% of the current backoff (which
    154     // increases by * multiplier up to max_backoff).
    155     const grpc_millis timeout_millis = next - grpc_core::ExecCtx::Get()->Now();
    156     EXPECT_GE(timeout_millis, expected_next_lower_bound);
    157     EXPECT_LE(timeout_millis, expected_next_upper_bound);
    158     current_backoff =
    159         std::min(static_cast<grpc_millis>(static_cast<double>(current_backoff) *
    160                                           multiplier),
    161                  max_backoff);
    162     expected_next_lower_bound = static_cast<grpc_millis>(
    163         static_cast<double>(current_backoff) * (1 - jitter));
    164     expected_next_upper_bound = static_cast<grpc_millis>(
    165         static_cast<double>(current_backoff) * (1 + jitter));
    166   }
    167 }
    168 
    169 }  // namespace
    170 }  // namespace testing
    171 }  // namespace grpc
    172 
    173 int main(int argc, char** argv) {
    174   grpc_test_init(argc, argv);
    175   ::testing::InitGoogleTest(&argc, argv);
    176   return RUN_ALL_TESTS();
    177 }
    178