xref: /aosp_15_r20/external/cronet/net/base/backoff_entry_serializer_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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