1 // Copyright 2015 The Chromium Authors
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/containers/span.h"
8 #include "base/logging.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/time/tick_clock.h"
12 #include "base/time/time.h"
13 #include "base/values.h"
14 #include "net/base/backoff_entry_serializer.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16
17 namespace net {
18
19 namespace {
20
21 using base::Time;
22 using base::TimeTicks;
23
24 const Time kParseTime = Time::FromMillisecondsSinceUnixEpoch(
25 1430907555111); // May 2015 for realism
26
27 BackoffEntry::Policy base_policy = {
28 0 /* num_errors_to_ignore */,
29 1000 /* initial_delay_ms */,
30 2.0 /* multiply_factor */,
31 0.0 /* jitter_factor */,
32 20000 /* maximum_backoff_ms */,
33 2000 /* entry_lifetime_ms */,
34 false /* always_use_initial_delay */
35 };
36
37 class TestTickClock : public base::TickClock {
38 public:
39 TestTickClock() = default;
40 TestTickClock(const TestTickClock&) = delete;
41 TestTickClock& operator=(const TestTickClock&) = delete;
42 ~TestTickClock() override = default;
43
NowTicks() const44 TimeTicks NowTicks() const override { return now_ticks_; }
set_now(TimeTicks now)45 void set_now(TimeTicks now) { now_ticks_ = now; }
46
47 private:
48 TimeTicks now_ticks_;
49 };
50
51 // This test exercises the code that computes the "backoff duration" and tests
52 // BackoffEntrySerializer::SerializeToList computes the backoff duration of a
53 // BackoffEntry by subtracting two base::TimeTicks values. Note that
54 // base::TimeTicks::operator- does not protect against overflow. Because
55 // SerializeToList never returns null, its resolution strategy is to default to
56 // a zero base::TimeDelta when the subtraction would overflow.
TEST(BackoffEntrySerializerTest,SpecialCasesOfBackoffDuration)57 TEST(BackoffEntrySerializerTest, SpecialCasesOfBackoffDuration) {
58 const base::TimeTicks kZeroTicks;
59
60 struct TestCase {
61 base::TimeTicks release_time;
62 base::TimeTicks timeticks_now;
63 base::TimeDelta expected_backoff_duration;
64 };
65 TestCase test_cases[] = {
66 // Non-overflowing subtraction works as expected.
67 {
68 .release_time = kZeroTicks + base::Microseconds(100),
69 .timeticks_now = kZeroTicks + base::Microseconds(75),
70 .expected_backoff_duration = base::Microseconds(25),
71 },
72 {
73 .release_time = kZeroTicks + base::Microseconds(25),
74 .timeticks_now = kZeroTicks + base::Microseconds(100),
75 .expected_backoff_duration = base::Microseconds(-75),
76 },
77 // Defaults to zero when one of the operands is +/- infinity.
78 {
79 .release_time = base::TimeTicks::Min(),
80 .timeticks_now = kZeroTicks,
81 .expected_backoff_duration = base::TimeDelta(),
82 },
83 {
84 .release_time = base::TimeTicks::Max(),
85 .timeticks_now = kZeroTicks,
86 .expected_backoff_duration = base::TimeDelta(),
87 },
88 {
89 .release_time = kZeroTicks,
90 .timeticks_now = base::TimeTicks::Min(),
91 .expected_backoff_duration = base::TimeDelta(),
92 },
93 {
94 .release_time = kZeroTicks,
95 .timeticks_now = base::TimeTicks::Max(),
96 .expected_backoff_duration = base::TimeDelta(),
97 },
98 // Defaults to zero when both of the operands are +/- infinity.
99 {
100 .release_time = base::TimeTicks::Min(),
101 .timeticks_now = base::TimeTicks::Min(),
102 .expected_backoff_duration = base::TimeDelta(),
103 },
104 {
105 .release_time = base::TimeTicks::Min(),
106 .timeticks_now = base::TimeTicks::Max(),
107 .expected_backoff_duration = base::TimeDelta(),
108 },
109 {
110 .release_time = base::TimeTicks::Max(),
111 .timeticks_now = base::TimeTicks::Min(),
112 .expected_backoff_duration = base::TimeDelta(),
113 },
114 {
115 .release_time = base::TimeTicks::Max(),
116 .timeticks_now = base::TimeTicks::Max(),
117 .expected_backoff_duration = base::TimeDelta(),
118 },
119 // Defaults to zero when the subtraction overflows, even when neither
120 // operand is infinity.
121 {
122 .release_time = base::TimeTicks::Max() - base::Microseconds(1),
123 .timeticks_now = kZeroTicks + base::Microseconds(-1),
124 .expected_backoff_duration = base::TimeDelta(),
125 },
126 };
127
128 size_t test_index = 0;
129 for (const TestCase& test_case : test_cases) {
130 SCOPED_TRACE(base::StringPrintf("Running test case #%zu", test_index));
131 ++test_index;
132
133 Time original_time = base::Time::Now();
134 TestTickClock original_ticks;
135 original_ticks.set_now(test_case.timeticks_now);
136 BackoffEntry original(&base_policy, &original_ticks);
137 // Set the custom release time.
138 original.SetCustomReleaseTime(test_case.release_time);
139 base::Value::List serialized =
140 BackoffEntrySerializer::SerializeToList(original, original_time);
141
142 // Check that the serialized backoff duration matches our expectation.
143 const std::string& serialized_backoff_duration_string =
144 serialized[2].GetString();
145 int64_t serialized_backoff_duration_us;
146 EXPECT_TRUE(base::StringToInt64(serialized_backoff_duration_string,
147 &serialized_backoff_duration_us));
148
149 base::TimeDelta serialized_backoff_duration =
150 base::Microseconds(serialized_backoff_duration_us);
151 EXPECT_EQ(serialized_backoff_duration, test_case.expected_backoff_duration);
152 }
153 }
154
155 // This test verifies that BackoffEntrySerializer::SerializeToList will not
156 // serialize an infinite release time.
157 //
158 // In pseudocode, this is how absolute_release_time is computed:
159 // backoff_duration = release_time - now;
160 // absolute_release_time = backoff_duration + original_time;
161 //
162 // This test induces backoff_duration to be a nonzero duration and directly sets
163 // original_time as a large value, such that their addition will overflow.
TEST(BackoffEntrySerializerTest,SerializeFiniteReleaseTime)164 TEST(BackoffEntrySerializerTest, SerializeFiniteReleaseTime) {
165 const TimeTicks release_time = TimeTicks() + base::Microseconds(5);
166 const Time original_time = Time::Max() - base::Microseconds(4);
167
168 TestTickClock original_ticks;
169 original_ticks.set_now(TimeTicks());
170 BackoffEntry original(&base_policy, &original_ticks);
171 original.SetCustomReleaseTime(release_time);
172 base::Value::List serialized =
173 BackoffEntrySerializer::SerializeToList(original, original_time);
174
175 // Reach into the serialization and check the string-formatted release time.
176 const std::string& serialized_release_time = serialized[3].GetString();
177 EXPECT_EQ(serialized_release_time, "0");
178
179 // Test that |DeserializeFromList| notices this zero-valued release time and
180 // does not take it at face value.
181 std::unique_ptr<BackoffEntry> deserialized =
182 BackoffEntrySerializer::DeserializeFromList(serialized, &base_policy,
183 &original_ticks, kParseTime);
184 ASSERT_TRUE(deserialized.get());
185 EXPECT_EQ(original.GetReleaseTime(), deserialized->GetReleaseTime());
186 }
187
TEST(BackoffEntrySerializerTest,SerializeNoFailures)188 TEST(BackoffEntrySerializerTest, SerializeNoFailures) {
189 Time original_time = Time::Now();
190 TestTickClock original_ticks;
191 original_ticks.set_now(TimeTicks::Now());
192 BackoffEntry original(&base_policy, &original_ticks);
193 base::Value::List serialized =
194 BackoffEntrySerializer::SerializeToList(original, original_time);
195
196 std::unique_ptr<BackoffEntry> deserialized =
197 BackoffEntrySerializer::DeserializeFromList(
198 serialized, &base_policy, &original_ticks, original_time);
199 ASSERT_TRUE(deserialized.get());
200 EXPECT_EQ(original.failure_count(), deserialized->failure_count());
201 EXPECT_EQ(original.GetReleaseTime(), deserialized->GetReleaseTime());
202 }
203
204 // Test that deserialization fails instead of producing an entry with an
205 // infinite release time. (Regression test for https://crbug.com/1293904)
TEST(BackoffEntrySerializerTest,DeserializeNeverInfiniteReleaseTime)206 TEST(BackoffEntrySerializerTest, DeserializeNeverInfiniteReleaseTime) {
207 base::Value::List serialized;
208 serialized.Append(2);
209 serialized.Append(2);
210 serialized.Append("-9223372036854775807");
211 serialized.Append("2");
212
213 TestTickClock original_ticks;
214 original_ticks.set_now(base::TimeTicks() + base::Microseconds(-1));
215
216 base::Time time_now =
217 base::Time::FromDeltaSinceWindowsEpoch(base::Microseconds(-1));
218
219 std::unique_ptr<BackoffEntry> entry =
220 BackoffEntrySerializer::DeserializeFromList(serialized, &base_policy,
221 &original_ticks, time_now);
222 ASSERT_FALSE(entry);
223 }
224
TEST(BackoffEntrySerializerTest,SerializeTimeOffsets)225 TEST(BackoffEntrySerializerTest, SerializeTimeOffsets) {
226 Time original_time = Time::FromMillisecondsSinceUnixEpoch(
227 1430907555111); // May 2015 for realism
228 TestTickClock original_ticks;
229 BackoffEntry original(&base_policy, &original_ticks);
230 // 2 errors.
231 original.InformOfRequest(false);
232 original.InformOfRequest(false);
233 base::Value::List serialized =
234 BackoffEntrySerializer::SerializeToList(original, original_time);
235
236 {
237 // Test that immediate deserialization round-trips.
238 std::unique_ptr<BackoffEntry> deserialized =
239 BackoffEntrySerializer::DeserializeFromList(
240 serialized, &base_policy, &original_ticks, original_time);
241 ASSERT_TRUE(deserialized.get());
242 EXPECT_EQ(original.failure_count(), deserialized->failure_count());
243 EXPECT_EQ(original.GetReleaseTime(), deserialized->GetReleaseTime());
244 }
245
246 {
247 // Test deserialization when wall clock has advanced but TimeTicks::Now()
248 // hasn't (e.g. device was rebooted).
249 Time later_time = original_time + base::Days(1);
250 std::unique_ptr<BackoffEntry> deserialized =
251 BackoffEntrySerializer::DeserializeFromList(
252 serialized, &base_policy, &original_ticks, later_time);
253 ASSERT_TRUE(deserialized.get());
254 EXPECT_EQ(original.failure_count(), deserialized->failure_count());
255 // Remaining backoff duration continues decreasing while device is off.
256 // Since TimeTicks::Now() has not advanced, the absolute release time ticks
257 // will decrease accordingly.
258 EXPECT_GT(original.GetTimeUntilRelease(),
259 deserialized->GetTimeUntilRelease());
260 EXPECT_EQ(original.GetReleaseTime() - base::Days(1),
261 deserialized->GetReleaseTime());
262 }
263
264 {
265 // Test deserialization when TimeTicks::Now() has advanced but wall clock
266 // hasn't (e.g. it's an hour later, but a DST change cancelled that out).
267 TestTickClock later_ticks;
268 later_ticks.set_now(TimeTicks() + base::Days(1));
269 std::unique_ptr<BackoffEntry> deserialized =
270 BackoffEntrySerializer::DeserializeFromList(
271 serialized, &base_policy, &later_ticks, original_time);
272 ASSERT_TRUE(deserialized.get());
273 EXPECT_EQ(original.failure_count(), deserialized->failure_count());
274 // According to the wall clock, no time has passed. So remaining backoff
275 // duration is preserved, hence the absolute release time ticks increases.
276 // This isn't ideal - by also serializing the current time and time ticks,
277 // it would be possible to detect that time has passed but the wall clock
278 // went backwards, and reduce the remaining backoff duration accordingly,
279 // however the current implementation does not do this as the benefit would
280 // be somewhat marginal.
281 EXPECT_EQ(original.GetTimeUntilRelease(),
282 deserialized->GetTimeUntilRelease());
283 EXPECT_EQ(original.GetReleaseTime() + base::Days(1),
284 deserialized->GetReleaseTime());
285 }
286
287 {
288 // Test deserialization when both wall clock and TimeTicks::Now() have
289 // advanced (e.g. it's just later than it used to be).
290 TestTickClock later_ticks;
291 later_ticks.set_now(TimeTicks() + base::Days(1));
292 Time later_time = original_time + base::Days(1);
293 std::unique_ptr<BackoffEntry> deserialized =
294 BackoffEntrySerializer::DeserializeFromList(serialized, &base_policy,
295 &later_ticks, later_time);
296 ASSERT_TRUE(deserialized.get());
297 EXPECT_EQ(original.failure_count(), deserialized->failure_count());
298 // Since both have advanced by the same amount, the absolute release time
299 // ticks should be preserved; the remaining backoff duration will have
300 // decreased of course, since time has passed.
301 EXPECT_GT(original.GetTimeUntilRelease(),
302 deserialized->GetTimeUntilRelease());
303 EXPECT_EQ(original.GetReleaseTime(), deserialized->GetReleaseTime());
304 }
305
306 {
307 // Test deserialization when wall clock has gone backwards but TimeTicks
308 // haven't (e.g. the system clock was fast but they fixed it).
309 EXPECT_LT(base::Seconds(1), original.GetTimeUntilRelease());
310 Time earlier_time = original_time - base::Seconds(1);
311 std::unique_ptr<BackoffEntry> deserialized =
312 BackoffEntrySerializer::DeserializeFromList(
313 serialized, &base_policy, &original_ticks, earlier_time);
314 ASSERT_TRUE(deserialized.get());
315 EXPECT_EQ(original.failure_count(), deserialized->failure_count());
316 // If only the absolute wall clock time was serialized, subtracting the
317 // (decreased) current wall clock time from the serialized wall clock time
318 // could give very large (incorrect) values for remaining backoff duration.
319 // But instead the implementation also serializes the remaining backoff
320 // duration, and doesn't allow the duration to increase beyond it's previous
321 // value during deserialization. Hence when the wall clock goes backwards
322 // the remaining backoff duration will be preserved.
323 EXPECT_EQ(original.GetTimeUntilRelease(),
324 deserialized->GetTimeUntilRelease());
325 // Since TimeTicks::Now() hasn't changed, the absolute release time ticks
326 // will be equal too in this particular case.
327 EXPECT_EQ(original.GetReleaseTime(), deserialized->GetReleaseTime());
328 }
329 }
330
TEST(BackoffEntrySerializerTest,DeserializeUnknownVersion)331 TEST(BackoffEntrySerializerTest, DeserializeUnknownVersion) {
332 base::Value::List serialized;
333 serialized.Append(0); // Format version that never existed
334 serialized.Append(0); // Failure count
335 serialized.Append(2.0); // Backoff duration
336 serialized.Append("1234"); // Absolute release time
337
338 auto deserialized = BackoffEntrySerializer::DeserializeFromList(
339 serialized, &base_policy, nullptr, kParseTime);
340 ASSERT_FALSE(deserialized);
341 }
342
TEST(BackoffEntrySerializerTest,DeserializeVersion1)343 TEST(BackoffEntrySerializerTest, DeserializeVersion1) {
344 base::Value::List serialized;
345 serialized.Append(SerializationFormatVersion::kVersion1);
346 serialized.Append(0); // Failure count
347 serialized.Append(2.0); // Backoff duration in seconds as double
348 serialized.Append("1234"); // Absolute release time
349
350 auto deserialized = BackoffEntrySerializer::DeserializeFromList(
351 serialized, &base_policy, nullptr, kParseTime);
352 ASSERT_TRUE(deserialized);
353 }
354
TEST(BackoffEntrySerializerTest,DeserializeVersion2)355 TEST(BackoffEntrySerializerTest, DeserializeVersion2) {
356 base::Value::List serialized;
357 serialized.Append(SerializationFormatVersion::kVersion2);
358 serialized.Append(0); // Failure count
359 serialized.Append("2000"); // Backoff duration
360 serialized.Append("1234"); // Absolute release time
361
362 auto deserialized = BackoffEntrySerializer::DeserializeFromList(
363 serialized, &base_policy, nullptr, kParseTime);
364 ASSERT_TRUE(deserialized);
365 }
366
TEST(BackoffEntrySerializerTest,DeserializeVersion2NegativeDuration)367 TEST(BackoffEntrySerializerTest, DeserializeVersion2NegativeDuration) {
368 base::Value::List serialized;
369 serialized.Append(SerializationFormatVersion::kVersion2);
370 serialized.Append(0); // Failure count
371 serialized.Append("-2000"); // Backoff duration
372 serialized.Append("1234"); // Absolute release time
373
374 auto deserialized = BackoffEntrySerializer::DeserializeFromList(
375 serialized, &base_policy, nullptr, kParseTime);
376 ASSERT_TRUE(deserialized);
377 }
378
TEST(BackoffEntrySerializerTest,DeserializeVersion1WrongDurationType)379 TEST(BackoffEntrySerializerTest, DeserializeVersion1WrongDurationType) {
380 base::Value::List serialized;
381 serialized.Append(SerializationFormatVersion::kVersion1);
382 serialized.Append(0); // Failure count
383 serialized.Append("2000"); // Backoff duration in seconds as double
384 serialized.Append("1234"); // Absolute release time
385
386 auto deserialized = BackoffEntrySerializer::DeserializeFromList(
387 serialized, &base_policy, nullptr, kParseTime);
388 ASSERT_FALSE(deserialized);
389 }
390
TEST(BackoffEntrySerializerTest,DeserializeVersion2WrongDurationType)391 TEST(BackoffEntrySerializerTest, DeserializeVersion2WrongDurationType) {
392 base::Value::List serialized;
393 serialized.Append(SerializationFormatVersion::kVersion2);
394 serialized.Append(0); // Failure count
395 serialized.Append(2.0); // Backoff duration
396 serialized.Append("1234"); // Absolute release time
397
398 auto deserialized = BackoffEntrySerializer::DeserializeFromList(
399 serialized, &base_policy, nullptr, kParseTime);
400 ASSERT_FALSE(deserialized);
401 }
402
403 } // namespace
404
405 } // namespace net
406