• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "net/nqe/observation_buffer.h"
11 
12 #include <stddef.h>
13 
14 #include <map>
15 #include <string>
16 #include <utility>
17 #include <vector>
18 
19 #include "base/test/simple_test_tick_clock.h"
20 #include "base/time/time.h"
21 #include "net/nqe/network_quality_estimator_params.h"
22 #include "net/nqe/network_quality_observation.h"
23 #include "net/nqe/network_quality_observation_source.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 
26 namespace net::nqe::internal {
27 
28 namespace {
29 
30 // Verify that the buffer size is never exceeded.
TEST(NetworkQualityObservationBufferTest,BoundedBuffer)31 TEST(NetworkQualityObservationBufferTest, BoundedBuffer) {
32   std::map<std::string, std::string> variation_params;
33   NetworkQualityEstimatorParams params(variation_params);
34   base::SimpleTestTickClock tick_clock;
35   tick_clock.Advance(base::Minutes(1));
36   ObservationBuffer observation_buffer(&params, &tick_clock, 1.0, 1.0);
37   const base::TimeTicks now = base::TimeTicks() + base::Seconds(1);
38   for (int i = 1; i <= 1000; ++i) {
39     observation_buffer.AddObservation(
40         Observation(i, now, INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_TCP));
41     // The number of entries should be at most the maximum buffer size.
42     EXPECT_GE(300u, observation_buffer.Size());
43   }
44 }
45 
46 // Verify that the percentiles are monotonically non-decreasing when a weight is
47 // applied.
TEST(NetworkQualityObservationBufferTest,GetPercentileWithWeights)48 TEST(NetworkQualityObservationBufferTest, GetPercentileWithWeights) {
49   std::map<std::string, std::string> variation_params;
50   NetworkQualityEstimatorParams params(variation_params);
51   base::SimpleTestTickClock tick_clock;
52   tick_clock.Advance(base::Minutes(1));
53 
54   ObservationBuffer observation_buffer(&params, &tick_clock, 0.98, 1.0);
55   const base::TimeTicks now = tick_clock.NowTicks();
56   for (int i = 1; i <= 100; ++i) {
57     tick_clock.Advance(base::Seconds(1));
58     observation_buffer.AddObservation(
59         Observation(i, tick_clock.NowTicks(), INT32_MIN,
60                     NETWORK_QUALITY_OBSERVATION_SOURCE_TCP));
61   }
62   EXPECT_EQ(100U, observation_buffer.Size());
63 
64   int32_t result_lowest = INT32_MAX;
65   int32_t result_highest = INT32_MIN;
66 
67   for (int i = 1; i <= 100; ++i) {
68     size_t observations_count = 0;
69     // Verify that i'th percentile is more than i-1'th percentile.
70     std::optional<int32_t> result_i = observation_buffer.GetPercentile(
71         now, INT32_MIN, i, &observations_count);
72     EXPECT_EQ(100u, observations_count);
73     ASSERT_TRUE(result_i.has_value());
74     result_lowest = std::min(result_lowest, result_i.value());
75 
76     result_highest = std::max(result_highest, result_i.value());
77 
78     std::optional<int32_t> result_i_1 = observation_buffer.GetPercentile(
79         now, INT32_MIN, i - 1, &observations_count);
80     EXPECT_EQ(100u, observations_count);
81     ASSERT_TRUE(result_i_1.has_value());
82 
83     EXPECT_LE(result_i_1.value(), result_i.value());
84   }
85   EXPECT_LT(result_lowest, result_highest);
86 }
87 
88 // Verifies that the percentiles are correctly computed. All observations have
89 // the same timestamp.
TEST(NetworkQualityObservationBufferTest,PercentileSameTimestamps)90 TEST(NetworkQualityObservationBufferTest, PercentileSameTimestamps) {
91   std::map<std::string, std::string> variation_params;
92   NetworkQualityEstimatorParams params(variation_params);
93   base::SimpleTestTickClock tick_clock;
94   tick_clock.Advance(base::Minutes(1));
95   ObservationBuffer buffer(&params, &tick_clock, 0.5, 1.0);
96   ASSERT_EQ(0u, buffer.Size());
97   ASSERT_LT(0u, buffer.Capacity());
98 
99   const base::TimeTicks now = tick_clock.NowTicks();
100 
101   size_t observations_count = 0;
102   // Percentiles should be unavailable when no observations are available.
103   EXPECT_FALSE(
104       buffer
105           .GetPercentile(base::TimeTicks(), INT32_MIN, 50,
106                          &observations_count)
107           .has_value());
108   EXPECT_EQ(0u, observations_count);
109 
110   // Insert samples from {1,2,3,..., 100}. First insert odd samples, then even
111   // samples. This helps in verifying that the order of samples does not matter.
112   for (int i = 1; i <= 99; i += 2) {
113     buffer.AddObservation(Observation(i, now, INT32_MIN,
114                                       NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP));
115     EXPECT_TRUE(buffer.GetPercentile(base::TimeTicks(), INT32_MIN, 50, nullptr)
116                     .has_value());
117     ASSERT_EQ(static_cast<size_t>(i / 2 + 1), buffer.Size());
118   }
119 
120   for (int i = 2; i <= 100; i += 2) {
121     buffer.AddObservation(Observation(i, now, INT32_MIN,
122                                       NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP));
123     EXPECT_TRUE(buffer.GetPercentile(base::TimeTicks(), INT32_MIN, 50, nullptr)
124                     .has_value());
125     ASSERT_EQ(static_cast<size_t>(i / 2 + 50), buffer.Size());
126   }
127 
128   ASSERT_EQ(100u, buffer.Size());
129 
130   for (int i = 0; i <= 100; ++i) {
131     // Checks if the difference between actual result and the computed result is
132     // less than 1. This is required because computed percentiles may be
133     // slightly different from what is expected due to floating point
134     // computation errors and integer rounding off errors.
135     std::optional<int32_t> result = buffer.GetPercentile(
136         base::TimeTicks(), INT32_MIN, i, &observations_count);
137     EXPECT_EQ(100u, observations_count);
138     EXPECT_TRUE(result.has_value());
139     EXPECT_NEAR(result.value(), i, 1.0);
140   }
141 
142   EXPECT_FALSE(buffer
143                    .GetPercentile(now + base::Seconds(1), INT32_MIN, 50,
144                                   &observations_count)
145                    .has_value());
146   EXPECT_EQ(0u, observations_count);
147 
148   // Percentiles should be unavailable when no observations are available.
149   buffer.Clear();
150   EXPECT_FALSE(
151       buffer
152           .GetPercentile(base::TimeTicks(), INT32_MIN, 50,
153                          &observations_count)
154           .has_value());
155   EXPECT_EQ(0u, observations_count);
156 }
157 
158 // Verifies that the percentiles are correctly computed. Observations have
159 // different timestamps with half the observations being very old and the rest
160 // of them being very recent. Percentiles should factor in recent observations
161 // much more heavily than older samples.
TEST(NetworkQualityObservationBufferTest,PercentileDifferentTimestamps)162 TEST(NetworkQualityObservationBufferTest, PercentileDifferentTimestamps) {
163   std::map<std::string, std::string> variation_params;
164   NetworkQualityEstimatorParams params(variation_params);
165   base::SimpleTestTickClock tick_clock;
166   tick_clock.Advance(base::Minutes(1));
167   ObservationBuffer buffer(&params, &tick_clock, 0.5, 1.0);
168   const base::TimeTicks now = tick_clock.NowTicks();
169   const base::TimeTicks very_old = now - base::Days(7);
170 
171   size_t observations_count;
172 
173   // Network quality should be unavailable when no observations are available.
174   EXPECT_FALSE(
175       buffer
176           .GetPercentile(base::TimeTicks(), INT32_MIN, 50,
177                          &observations_count)
178           .has_value());
179   EXPECT_EQ(0u, observations_count);
180 
181   // First 50 samples have very old timestamps.
182   for (int i = 1; i <= 50; ++i) {
183     buffer.AddObservation(Observation(i, very_old, INT32_MIN,
184                                       NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP));
185   }
186 
187   // Next 50 (i.e., from 51 to 100) have recent timestamps.
188   for (int i = 51; i <= 100; ++i) {
189     buffer.AddObservation(Observation(i, now, INT32_MIN,
190                                       NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP));
191   }
192 
193   // Older samples have very little weight. So, all percentiles are >= 51
194   // (lowest value among recent observations).
195   for (int i = 1; i < 100; ++i) {
196     // Checks if the difference between the two integers is less than 1. This is
197     // required because computed percentiles may be slightly different from
198     // what is expected due to floating point computation errors and integer
199     // rounding off errors.
200     std::optional<int32_t> result =
201         buffer.GetPercentile(very_old, INT32_MIN, i, &observations_count);
202     EXPECT_TRUE(result.has_value());
203     EXPECT_NEAR(result.value(), 51 + 0.49 * i, 1);
204     EXPECT_EQ(100u, observations_count);
205   }
206 
207   EXPECT_FALSE(buffer.GetPercentile(now + base::Seconds(1), INT32_MIN, 50,
208                                     &observations_count));
209   EXPECT_EQ(0u, observations_count);
210 }
211 
212 // Verifies that the percentiles are correctly computed. All observations have
213 // same timestamp with half the observations taken at low RSSI, and half the
214 // observations with high RSSI. Percentiles should be computed based on the
215 // current RSSI and the RSSI of the observations.
TEST(NetworkQualityObservationBufferTest,PercentileDifferentRSSI)216 TEST(NetworkQualityObservationBufferTest, PercentileDifferentRSSI) {
217   std::map<std::string, std::string> variation_params;
218   NetworkQualityEstimatorParams params(variation_params);
219   base::SimpleTestTickClock tick_clock;
220   tick_clock.Advance(base::Minutes(1));
221   ObservationBuffer buffer(&params, &tick_clock, 1.0, 0.25);
222   const base::TimeTicks now = tick_clock.NowTicks();
223   int32_t high_rssi = 4;
224   int32_t low_rssi = 0;
225 
226   // Network quality should be unavailable when no observations are available.
227   EXPECT_FALSE(buffer.GetPercentile(base::TimeTicks(), INT32_MIN, 50, nullptr)
228                    .has_value());
229 
230   // First 50 samples have very low RSSI.
231   for (int i = 1; i <= 50; ++i) {
232     buffer.AddObservation(
233         Observation(i, now, low_rssi, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP));
234   }
235 
236   // Next 50 (i.e., from 51 to 100) have high RSSI.
237   for (int i = 51; i <= 100; ++i) {
238     buffer.AddObservation(Observation(i, now, high_rssi,
239                                       NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP));
240   }
241 
242   // When the current RSSI is |high_rssi|, higher weight should be assigned
243   // to observations that were taken at |high_rssi|.
244   for (int i = 1; i < 100; ++i) {
245     std::optional<int32_t> result =
246         buffer.GetPercentile(now, high_rssi, i, nullptr);
247     EXPECT_TRUE(result.has_value());
248     EXPECT_NEAR(result.value(), 51 + 0.49 * i, 2);
249   }
250 
251   // When the current RSSI is |low_rssi|, higher weight should be assigned
252   // to observations that were taken at |low_rssi|.
253   for (int i = 1; i < 100; ++i) {
254     std::optional<int32_t> result =
255         buffer.GetPercentile(now, low_rssi, i, nullptr);
256     EXPECT_TRUE(result.has_value());
257     EXPECT_NEAR(result.value(), i / 2, 2);
258   }
259 }
260 
261 // Verifies that the percentiles are correctly computed when some of the
262 // observation sources are disallowed. All observations have the same timestamp.
TEST(NetworkQualityObservationBufferTest,RemoveObservations)263 TEST(NetworkQualityObservationBufferTest, RemoveObservations) {
264   std::map<std::string, std::string> variation_params;
265   NetworkQualityEstimatorParams params(variation_params);
266   base::SimpleTestTickClock tick_clock;
267   tick_clock.Advance(base::Minutes(1));
268 
269   ObservationBuffer buffer(&params, &tick_clock, 0.5, 1.0);
270   const base::TimeTicks now = tick_clock.NowTicks();
271 
272   // Insert samples from {1,2,3,..., 100}. First insert odd samples, then even
273   // samples. This helps in verifying that the order of samples does not matter.
274   for (int i = 1; i <= 99; i += 2) {
275     buffer.AddObservation(Observation(i, now, INT32_MIN,
276                                       NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP));
277   }
278   EXPECT_EQ(50u, buffer.Size());
279 
280   // Add samples for TCP and QUIC observations which should not be taken into
281   // account when computing the percentile.
282   for (int i = 1; i <= 99; i += 2) {
283     buffer.AddObservation(Observation(10000, now, INT32_MIN,
284                                       NETWORK_QUALITY_OBSERVATION_SOURCE_TCP));
285     buffer.AddObservation(Observation(10000, now, INT32_MIN,
286                                       NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC));
287   }
288   EXPECT_EQ(150u, buffer.Size());
289 
290   for (int i = 2; i <= 100; i += 2) {
291     buffer.AddObservation(Observation(i, now, INT32_MIN,
292                                       NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP));
293   }
294   EXPECT_EQ(200u, buffer.Size());
295 
296   bool deleted_observation_sources[NETWORK_QUALITY_OBSERVATION_SOURCE_MAX] = {
297       false};
298 
299   // Since all entries in |deleted_observation_sources| are set to false, no
300   // observations should be deleted.
301   buffer.RemoveObservationsWithSource(deleted_observation_sources);
302   EXPECT_EQ(200u, buffer.Size());
303 
304   // 50 TCP and 50 QUIC observations should be deleted.
305   deleted_observation_sources[NETWORK_QUALITY_OBSERVATION_SOURCE_TCP] = true;
306   deleted_observation_sources[NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC] = true;
307   buffer.RemoveObservationsWithSource(deleted_observation_sources);
308   EXPECT_EQ(100u, buffer.Size());
309 
310   for (int i = 0; i <= 100; ++i) {
311     // Checks if the difference between the two integers is less than 1. This is
312     // required because computed percentiles may be slightly different from
313     // what is expected due to floating point computation errors and integer
314     // rounding off errors.
315     std::optional<int32_t> result =
316         buffer.GetPercentile(base::TimeTicks(), INT32_MIN, i, nullptr);
317     EXPECT_TRUE(result.has_value());
318     EXPECT_NEAR(result.value(), i, 1);
319   }
320 
321   deleted_observation_sources[NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP] = true;
322   buffer.RemoveObservationsWithSource(deleted_observation_sources);
323   EXPECT_EQ(0u, buffer.Size());
324 }
325 
TEST(NetworkQualityObservationBufferTest,TestGetMedianRTTSince)326 TEST(NetworkQualityObservationBufferTest, TestGetMedianRTTSince) {
327   std::map<std::string, std::string> variation_params;
328   NetworkQualityEstimatorParams params(variation_params);
329   base::SimpleTestTickClock tick_clock;
330   tick_clock.Advance(base::Minutes(1));
331   ObservationBuffer buffer(&params, &tick_clock, 0.5, 1.0);
332   base::TimeTicks now = tick_clock.NowTicks();
333   base::TimeTicks old = now - base::Milliseconds(1);
334   ASSERT_NE(old, now);
335 
336   // First sample has very old timestamp.
337   buffer.AddObservation(
338       Observation(1, old, INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP));
339 
340   buffer.AddObservation(Observation(100, now, INT32_MIN,
341                                     NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP));
342 
343   const struct {
344     base::TimeTicks start_timestamp;
345     bool expect_network_quality_available;
346     base::TimeDelta expected_url_request_rtt;
347   } tests[] = {
348       {now + base::Seconds(10), false, base::Milliseconds(0)},
349       {now, true, base::Milliseconds(100)},
350       {now - base::Microseconds(500), true, base::Milliseconds(100)},
351 
352   };
353 
354   for (const auto& test : tests) {
355     std::optional<int32_t> url_request_rtt =
356         buffer.GetPercentile(test.start_timestamp, INT32_MIN, 50, nullptr);
357     EXPECT_EQ(test.expect_network_quality_available,
358               url_request_rtt.has_value());
359 
360     if (test.expect_network_quality_available) {
361       EXPECT_EQ(test.expected_url_request_rtt.InMillisecondsF(),
362                 url_request_rtt.value());
363     }
364   }
365 }
366 
367 
368 }  // namespace
369 
370 }  // namespace net::nqe::internal
371