Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/base/backoff_entry.h"
      6 #include "testing/gtest/include/gtest/gtest.h"
      7 
      8 namespace {
      9 
     10 using base::TimeDelta;
     11 using base::TimeTicks;
     12 using net::BackoffEntry;
     13 
     14 BackoffEntry::Policy base_policy = { 0, 1000, 2.0, 0.0, 20000, 2000 };
     15 
     16 class TestBackoffEntry : public BackoffEntry {
     17  public:
     18   explicit TestBackoffEntry(const Policy* const policy)
     19       : BackoffEntry(policy),
     20         now_(TimeTicks()) {
     21     // Work around initialization in constructor not picking up
     22     // fake time.
     23     SetCustomReleaseTime(TimeTicks());
     24   }
     25 
     26   virtual ~TestBackoffEntry() {}
     27 
     28   virtual TimeTicks GetTimeNow() const {
     29     return now_;
     30   }
     31 
     32   void set_now(const TimeTicks& now) {
     33     now_ = now;
     34   }
     35 
     36  private:
     37   TimeTicks now_;
     38 
     39   DISALLOW_COPY_AND_ASSIGN(TestBackoffEntry);
     40 };
     41 
     42 TEST(BackoffEntryTest, BaseTest) {
     43   TestBackoffEntry entry(&base_policy);
     44   EXPECT_FALSE(entry.ShouldRejectRequest());
     45 
     46   entry.InformOfRequest(false);
     47   EXPECT_TRUE(entry.ShouldRejectRequest());
     48 }
     49 
     50 TEST(BackoffEntryTest, CanDiscardNeverExpires) {
     51   BackoffEntry::Policy never_expires_policy = base_policy;
     52   never_expires_policy.entry_lifetime_ms = -1;
     53   TestBackoffEntry never_expires(&never_expires_policy);
     54   EXPECT_FALSE(never_expires.CanDiscard());
     55   never_expires.set_now(TimeTicks() + TimeDelta::FromDays(100));
     56   EXPECT_FALSE(never_expires.CanDiscard());
     57 }
     58 
     59 TEST(BackoffEntryTest, CanDiscard) {
     60   TestBackoffEntry entry(&base_policy);
     61   // Because lifetime is non-zero, we shouldn't be able to discard yet.
     62   EXPECT_FALSE(entry.CanDiscard());
     63 
     64   // Test the "being used" case.
     65   entry.InformOfRequest(false);
     66   EXPECT_FALSE(entry.CanDiscard());
     67 
     68   // Test the case where there are errors but we can time out.
     69   entry.set_now(
     70       entry.GetReleaseTime() + TimeDelta::FromMilliseconds(1));
     71   EXPECT_FALSE(entry.CanDiscard());
     72   entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(
     73       base_policy.maximum_backoff_ms + 1));
     74   EXPECT_TRUE(entry.CanDiscard());
     75 
     76   // Test the final case (no errors, dependent only on specified lifetime).
     77   entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(
     78       base_policy.entry_lifetime_ms - 1));
     79   entry.InformOfRequest(true);
     80   EXPECT_FALSE(entry.CanDiscard());
     81   entry.set_now(entry.GetReleaseTime() + TimeDelta::FromMilliseconds(
     82       base_policy.entry_lifetime_ms));
     83   EXPECT_TRUE(entry.CanDiscard());
     84 }
     85 
     86 TEST(BackoffEntryTest, CanDiscardNotStored) {
     87   BackoffEntry::Policy no_store_policy = base_policy;
     88   no_store_policy.entry_lifetime_ms = 0;
     89   TestBackoffEntry not_stored(&no_store_policy);
     90   EXPECT_TRUE(not_stored.CanDiscard());
     91 }
     92 
     93 TEST(BackoffEntryTest, ShouldIgnoreFirstTwo) {
     94   BackoffEntry::Policy lenient_policy = base_policy;
     95   lenient_policy.num_errors_to_ignore = 2;
     96 
     97   BackoffEntry entry(&lenient_policy);
     98   entry.InformOfRequest(false);
     99   EXPECT_FALSE(entry.ShouldRejectRequest());
    100   entry.InformOfRequest(false);
    101   EXPECT_FALSE(entry.ShouldRejectRequest());
    102   entry.InformOfRequest(false);
    103   EXPECT_TRUE(entry.ShouldRejectRequest());
    104 }
    105 
    106 TEST(BackoffEntryTest, ReleaseTimeCalculation) {
    107   TestBackoffEntry entry(&base_policy);
    108 
    109   // With zero errors, should return "now".
    110   TimeTicks result = entry.GetReleaseTime();
    111   EXPECT_EQ(entry.GetTimeNow(), result);
    112 
    113   // 1 error.
    114   entry.InformOfRequest(false);
    115   result = entry.GetReleaseTime();
    116   EXPECT_EQ(entry.GetTimeNow() + TimeDelta::FromMilliseconds(1000), result);
    117 
    118   // 2 errors.
    119   entry.InformOfRequest(false);
    120   result = entry.GetReleaseTime();
    121   EXPECT_EQ(entry.GetTimeNow() + TimeDelta::FromMilliseconds(2000), result);
    122 
    123   // 3 errors.
    124   entry.InformOfRequest(false);
    125   result = entry.GetReleaseTime();
    126   EXPECT_EQ(entry.GetTimeNow() + TimeDelta::FromMilliseconds(4000), result);
    127 
    128   // 6 errors (to check it doesn't pass maximum).
    129   entry.InformOfRequest(false);
    130   entry.InformOfRequest(false);
    131   entry.InformOfRequest(false);
    132   result = entry.GetReleaseTime();
    133   EXPECT_EQ(entry.GetTimeNow() + TimeDelta::FromMilliseconds(20000), result);
    134 }
    135 
    136 TEST(BackoffEntryTest, ReleaseTimeCalculationWithJitter) {
    137   for (int i = 0; i < 10; ++i) {
    138     BackoffEntry::Policy jittery_policy = base_policy;
    139     jittery_policy.jitter_factor = 0.2;
    140 
    141     TestBackoffEntry entry(&jittery_policy);
    142 
    143     entry.InformOfRequest(false);
    144     entry.InformOfRequest(false);
    145     entry.InformOfRequest(false);
    146     TimeTicks result = entry.GetReleaseTime();
    147     EXPECT_LE(entry.GetTimeNow() + TimeDelta::FromMilliseconds(3200), result);
    148     EXPECT_GE(entry.GetTimeNow() + TimeDelta::FromMilliseconds(4000), result);
    149   }
    150 }
    151 
    152 TEST(BackoffEntryTest, FailureThenSuccess) {
    153   TestBackoffEntry entry(&base_policy);
    154 
    155   // Failure count 1, establishes horizon.
    156   entry.InformOfRequest(false);
    157   TimeTicks release_time = entry.GetReleaseTime();
    158   EXPECT_EQ(TimeTicks() + TimeDelta::FromMilliseconds(1000), release_time);
    159 
    160   // Success, failure count 0, should not advance past
    161   // the horizon that was already set.
    162   entry.set_now(release_time - TimeDelta::FromMilliseconds(200));
    163   entry.InformOfRequest(true);
    164   EXPECT_EQ(release_time, entry.GetReleaseTime());
    165 
    166   // Failure, failure count 1.
    167   entry.InformOfRequest(false);
    168   EXPECT_EQ(release_time + TimeDelta::FromMilliseconds(800),
    169             entry.GetReleaseTime());
    170 }
    171 
    172 TEST(BackoffEntryTest, RetainCustomHorizon) {
    173   TestBackoffEntry custom(&base_policy);
    174   TimeTicks custom_horizon = TimeTicks() + TimeDelta::FromDays(3);
    175   custom.SetCustomReleaseTime(custom_horizon);
    176   custom.InformOfRequest(false);
    177   custom.InformOfRequest(true);
    178   custom.set_now(TimeTicks() + TimeDelta::FromDays(2));
    179   custom.InformOfRequest(false);
    180   custom.InformOfRequest(true);
    181   EXPECT_EQ(custom_horizon, custom.GetReleaseTime());
    182 
    183   // Now check that once we are at or past the custom horizon,
    184   // we get normal behavior.
    185   custom.set_now(TimeTicks() + TimeDelta::FromDays(3));
    186   custom.InformOfRequest(false);
    187   EXPECT_EQ(
    188       TimeTicks() + TimeDelta::FromDays(3) + TimeDelta::FromMilliseconds(1000),
    189       custom.GetReleaseTime());
    190 }
    191 
    192 TEST(BackoffEntryTest, RetainCustomHorizonWhenInitialErrorsIgnored) {
    193   // Regression test for a bug discovered during code review.
    194   BackoffEntry::Policy lenient_policy = base_policy;
    195   lenient_policy.num_errors_to_ignore = 1;
    196   TestBackoffEntry custom(&lenient_policy);
    197   TimeTicks custom_horizon = TimeTicks() + TimeDelta::FromDays(3);
    198   custom.SetCustomReleaseTime(custom_horizon);
    199   custom.InformOfRequest(false);  // This must not reset the horizon.
    200   EXPECT_EQ(custom_horizon, custom.GetReleaseTime());
    201 }
    202 
    203 }  // namespace
    204