1 // Copyright 2015 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 
7 #include "base/time/tick_clock.h"
8 #include "base/values.h"
9 #include "net/base/backoff_entry_serializer.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 
12 namespace net {
13 
14 namespace {
15 
16 using base::Time;
17 using base::TimeDelta;
18 using base::TimeTicks;
19 
20 BackoffEntry::Policy base_policy = {
21   0 /* num_errors_to_ignore */,
22   1000 /* initial_delay_ms */,
23   2.0 /* multiply_factor */,
24   0.0 /* jitter_factor */,
25   20000 /* maximum_backoff_ms */,
26   2000 /* entry_lifetime_ms */,
27   false /* always_use_initial_delay */
28 };
29 
30 class TestTickClock : public base::TickClock {
31  public:
32   TestTickClock() = default;
33   TestTickClock(const TestTickClock&) = delete;
34   TestTickClock& operator=(const TestTickClock&) = delete;
35   ~TestTickClock() override = default;
36 
NowTicks() const37   TimeTicks NowTicks() const override { return now_ticks_; }
set_now(TimeTicks now)38   void set_now(TimeTicks now) { now_ticks_ = now; }
39 
40  private:
41   TimeTicks now_ticks_;
42 };
43 
TEST(BackoffEntrySerializerTest,SerializeNoFailures)44 TEST(BackoffEntrySerializerTest, SerializeNoFailures) {
45   Time original_time = Time::Now();
46   TestTickClock original_ticks;
47   original_ticks.set_now(TimeTicks::Now());
48   BackoffEntry original(&base_policy, &original_ticks);
49   std::unique_ptr<base::Value> serialized =
50       BackoffEntrySerializer::SerializeToValue(original, original_time);
51 
52   std::unique_ptr<BackoffEntry> deserialized =
53       BackoffEntrySerializer::DeserializeFromValue(
54           *serialized, &base_policy, &original_ticks, original_time);
55   ASSERT_TRUE(deserialized.get());
56   EXPECT_EQ(original.failure_count(), deserialized->failure_count());
57   EXPECT_EQ(original.GetReleaseTime(), deserialized->GetReleaseTime());
58 }
59 
TEST(BackoffEntrySerializerTest,SerializeTimeOffsets)60 TEST(BackoffEntrySerializerTest, SerializeTimeOffsets) {
61   Time original_time = Time::FromJsTime(1430907555111);  // May 2015 for realism
62   TestTickClock original_ticks;
63   BackoffEntry original(&base_policy, &original_ticks);
64   // 2 errors.
65   original.InformOfRequest(false);
66   original.InformOfRequest(false);
67   std::unique_ptr<base::Value> serialized =
68       BackoffEntrySerializer::SerializeToValue(original, original_time);
69 
70   {
71     // Test that immediate deserialization round-trips.
72     std::unique_ptr<BackoffEntry> deserialized =
73         BackoffEntrySerializer::DeserializeFromValue(
74             *serialized, &base_policy, &original_ticks, original_time);
75     ASSERT_TRUE(deserialized.get());
76     EXPECT_EQ(original.failure_count(), deserialized->failure_count());
77     EXPECT_EQ(original.GetReleaseTime(), deserialized->GetReleaseTime());
78   }
79 
80   {
81     // Test deserialization when wall clock has advanced but TimeTicks::Now()
82     // hasn't (e.g. device was rebooted).
83     Time later_time = original_time + TimeDelta::FromDays(1);
84     std::unique_ptr<BackoffEntry> deserialized =
85         BackoffEntrySerializer::DeserializeFromValue(
86             *serialized, &base_policy, &original_ticks, later_time);
87     ASSERT_TRUE(deserialized.get());
88     EXPECT_EQ(original.failure_count(), deserialized->failure_count());
89     // Remaining backoff duration continues decreasing while device is off.
90     // Since TimeTicks::Now() has not advanced, the absolute release time ticks
91     // will decrease accordingly.
92     EXPECT_GT(original.GetTimeUntilRelease(),
93               deserialized->GetTimeUntilRelease());
94     EXPECT_EQ(original.GetReleaseTime() - TimeDelta::FromDays(1),
95               deserialized->GetReleaseTime());
96   }
97 
98   {
99     // Test deserialization when TimeTicks::Now() has advanced but wall clock
100     // hasn't (e.g. it's an hour later, but a DST change cancelled that out).
101     TestTickClock later_ticks;
102     later_ticks.set_now(TimeTicks() + TimeDelta::FromDays(1));
103     std::unique_ptr<BackoffEntry> deserialized =
104         BackoffEntrySerializer::DeserializeFromValue(
105             *serialized, &base_policy, &later_ticks, original_time);
106     ASSERT_TRUE(deserialized.get());
107     EXPECT_EQ(original.failure_count(), deserialized->failure_count());
108     // According to the wall clock, no time has passed. So remaining backoff
109     // duration is preserved, hence the absolute release time ticks increases.
110     // This isn't ideal - by also serializing the current time and time ticks,
111     // it would be possible to detect that time has passed but the wall clock
112     // went backwards, and reduce the remaining backoff duration accordingly,
113     // however the current implementation does not do this as the benefit would
114     // be somewhat marginal.
115     EXPECT_EQ(original.GetTimeUntilRelease(),
116               deserialized->GetTimeUntilRelease());
117     EXPECT_EQ(original.GetReleaseTime() + TimeDelta::FromDays(1),
118               deserialized->GetReleaseTime());
119   }
120 
121   {
122     // Test deserialization when both wall clock and TimeTicks::Now() have
123     // advanced (e.g. it's just later than it used to be).
124     TestTickClock later_ticks;
125     later_ticks.set_now(TimeTicks() + TimeDelta::FromDays(1));
126     Time later_time = original_time + TimeDelta::FromDays(1);
127     std::unique_ptr<BackoffEntry> deserialized =
128         BackoffEntrySerializer::DeserializeFromValue(*serialized, &base_policy,
129                                                      &later_ticks, later_time);
130     ASSERT_TRUE(deserialized.get());
131     EXPECT_EQ(original.failure_count(), deserialized->failure_count());
132     // Since both have advanced by the same amount, the absolute release time
133     // ticks should be preserved; the remaining backoff duration will have
134     // decreased of course, since time has passed.
135     EXPECT_GT(original.GetTimeUntilRelease(),
136               deserialized->GetTimeUntilRelease());
137     EXPECT_EQ(original.GetReleaseTime(), deserialized->GetReleaseTime());
138   }
139 
140   {
141     // Test deserialization when wall clock has gone backwards but TimeTicks
142     // haven't (e.g. the system clock was fast but they fixed it).
143     EXPECT_LT(TimeDelta::FromSeconds(1), original.GetTimeUntilRelease());
144     Time earlier_time = original_time - TimeDelta::FromSeconds(1);
145     std::unique_ptr<BackoffEntry> deserialized =
146         BackoffEntrySerializer::DeserializeFromValue(
147             *serialized, &base_policy, &original_ticks, earlier_time);
148     ASSERT_TRUE(deserialized.get());
149     EXPECT_EQ(original.failure_count(), deserialized->failure_count());
150     // If only the absolute wall clock time was serialized, subtracting the
151     // (decreased) current wall clock time from the serialized wall clock time
152     // could give very large (incorrect) values for remaining backoff duration.
153     // But instead the implementation also serializes the remaining backoff
154     // duration, and doesn't allow the duration to increase beyond it's previous
155     // value during deserialization. Hence when the wall clock goes backwards
156     // the remaining backoff duration will be preserved.
157     EXPECT_EQ(original.GetTimeUntilRelease(),
158               deserialized->GetTimeUntilRelease());
159     // Since TimeTicks::Now() hasn't changed, the absolute release time ticks
160     // will be equal too in this particular case.
161     EXPECT_EQ(original.GetReleaseTime(), deserialized->GetReleaseTime());
162   }
163 }
164 
165 }  // namespace
166 
167 }  // namespace net
168