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