OLD | NEW |
| (Empty) |
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/network_quality_estimator.h" | |
6 | |
7 #include <stddef.h> | |
8 #include <stdint.h> | |
9 | |
10 #include <limits> | |
11 #include <map> | |
12 #include <memory> | |
13 #include <string> | |
14 #include <utility> | |
15 #include <vector> | |
16 | |
17 #include "base/files/file_path.h" | |
18 #include "base/logging.h" | |
19 #include "base/macros.h" | |
20 #include "base/metrics/histogram_samples.h" | |
21 #include "base/run_loop.h" | |
22 #include "base/strings/string_number_conversions.h" | |
23 #include "base/test/histogram_tester.h" | |
24 #include "base/time/time.h" | |
25 #include "build/build_config.h" | |
26 #include "net/base/external_estimate_provider.h" | |
27 #include "net/base/load_flags.h" | |
28 #include "net/base/network_change_notifier.h" | |
29 #include "net/base/socket_performance_watcher.h" | |
30 #include "net/base/socket_performance_watcher_factory.h" | |
31 #include "net/http/http_status_code.h" | |
32 #include "net/test/embedded_test_server/embedded_test_server.h" | |
33 #include "net/test/embedded_test_server/http_request.h" | |
34 #include "net/test/embedded_test_server/http_response.h" | |
35 #include "net/url_request/url_request.h" | |
36 #include "net/url_request/url_request_test_util.h" | |
37 #include "testing/gtest/include/gtest/gtest.h" | |
38 #include "url/gurl.h" | |
39 | |
40 namespace net { | |
41 | |
42 namespace { | |
43 | |
44 // Helps in setting the current network type and id. | |
45 class TestNetworkQualityEstimator : public NetworkQualityEstimator { | |
46 public: | |
47 TestNetworkQualityEstimator( | |
48 const std::map<std::string, std::string>& variation_params, | |
49 std::unique_ptr<ExternalEstimateProvider> external_estimate_provider) | |
50 : NetworkQualityEstimator(std::move(external_estimate_provider), | |
51 variation_params, | |
52 true, | |
53 true), | |
54 url_rtt_set_(false), | |
55 downlink_throughput_kbps_set_(false) { | |
56 // Set up embedded test server. | |
57 embedded_test_server_.ServeFilesFromDirectory( | |
58 base::FilePath(FILE_PATH_LITERAL("net/data/url_request_unittest"))); | |
59 EXPECT_TRUE(embedded_test_server_.Start()); | |
60 embedded_test_server_.RegisterRequestHandler(base::Bind( | |
61 &TestNetworkQualityEstimator::HandleRequest, base::Unretained(this))); | |
62 } | |
63 | |
64 explicit TestNetworkQualityEstimator( | |
65 const std::map<std::string, std::string>& variation_params) | |
66 : TestNetworkQualityEstimator( | |
67 variation_params, | |
68 std::unique_ptr<ExternalEstimateProvider>()) {} | |
69 | |
70 ~TestNetworkQualityEstimator() override {} | |
71 | |
72 // Overrides the current network type and id. | |
73 // Notifies network quality estimator of change in connection. | |
74 void SimulateNetworkChangeTo(NetworkChangeNotifier::ConnectionType type, | |
75 std::string network_id) { | |
76 current_network_type_ = type; | |
77 current_network_id_ = network_id; | |
78 OnConnectionTypeChanged(type); | |
79 } | |
80 | |
81 // Called by embedded server when a HTTP request is received. | |
82 std::unique_ptr<test_server::HttpResponse> HandleRequest( | |
83 const test_server::HttpRequest& request) { | |
84 std::unique_ptr<test_server::BasicHttpResponse> http_response( | |
85 new test_server::BasicHttpResponse()); | |
86 http_response->set_code(HTTP_OK); | |
87 http_response->set_content("hello"); | |
88 http_response->set_content_type("text/plain"); | |
89 return std::move(http_response); | |
90 } | |
91 | |
92 // Returns a GURL hosted at embedded test server. | |
93 const GURL GetEchoURL() const { | |
94 return embedded_test_server_.GetURL("/echo.html"); | |
95 } | |
96 | |
97 void set_url_rtt(const base::TimeDelta& url_rtt) { | |
98 url_rtt_set_ = true; | |
99 url_rtt_ = url_rtt; | |
100 } | |
101 | |
102 bool GetURLRequestRTTEstimate(base::TimeDelta* rtt) const override { | |
103 if (url_rtt_set_) { | |
104 *rtt = url_rtt_; | |
105 return true; | |
106 } | |
107 return NetworkQualityEstimator::GetURLRequestRTTEstimate(rtt); | |
108 } | |
109 | |
110 void set_downlink_throughput_kbps(int32_t downlink_throughput_kbps) { | |
111 downlink_throughput_kbps_set_ = true; | |
112 downlink_throughput_kbps_ = downlink_throughput_kbps; | |
113 } | |
114 | |
115 bool GetDownlinkThroughputKbpsEstimate(int32_t* kbps) const override { | |
116 if (downlink_throughput_kbps_set_) { | |
117 *kbps = downlink_throughput_kbps_; | |
118 return true; | |
119 } | |
120 return NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimate(kbps); | |
121 } | |
122 | |
123 using NetworkQualityEstimator::ReadCachedNetworkQualityEstimate; | |
124 using NetworkQualityEstimator::OnConnectionTypeChanged; | |
125 | |
126 private: | |
127 // NetworkQualityEstimator implementation that returns the overridden network | |
128 // id (instead of invoking platform APIs). | |
129 NetworkQualityEstimator::NetworkID GetCurrentNetworkID() const override { | |
130 return NetworkQualityEstimator::NetworkID(current_network_type_, | |
131 current_network_id_); | |
132 } | |
133 | |
134 NetworkChangeNotifier::ConnectionType current_network_type_; | |
135 std::string current_network_id_; | |
136 | |
137 bool url_rtt_set_; | |
138 base::TimeDelta url_rtt_; | |
139 | |
140 bool downlink_throughput_kbps_set_; | |
141 int32_t downlink_throughput_kbps_; | |
142 | |
143 // Embedded server used for testing. | |
144 EmbeddedTestServer embedded_test_server_; | |
145 | |
146 DISALLOW_COPY_AND_ASSIGN(TestNetworkQualityEstimator); | |
147 }; | |
148 | |
149 class TestRTTObserver : public NetworkQualityEstimator::RTTObserver { | |
150 public: | |
151 struct Observation { | |
152 Observation(int32_t ms, | |
153 const base::TimeTicks& ts, | |
154 NetworkQualityEstimator::ObservationSource src) | |
155 : rtt_ms(ms), timestamp(ts), source(src) {} | |
156 int32_t rtt_ms; | |
157 base::TimeTicks timestamp; | |
158 NetworkQualityEstimator::ObservationSource source; | |
159 }; | |
160 | |
161 std::vector<Observation>& observations() { return observations_; } | |
162 | |
163 // RttObserver implementation: | |
164 void OnRTTObservation( | |
165 int32_t rtt_ms, | |
166 const base::TimeTicks& timestamp, | |
167 NetworkQualityEstimator::ObservationSource source) override { | |
168 observations_.push_back(Observation(rtt_ms, timestamp, source)); | |
169 } | |
170 | |
171 private: | |
172 std::vector<Observation> observations_; | |
173 }; | |
174 | |
175 class TestThroughputObserver | |
176 : public NetworkQualityEstimator::ThroughputObserver { | |
177 public: | |
178 struct Observation { | |
179 Observation(int32_t kbps, | |
180 const base::TimeTicks& ts, | |
181 NetworkQualityEstimator::ObservationSource src) | |
182 : throughput_kbps(kbps), timestamp(ts), source(src) {} | |
183 int32_t throughput_kbps; | |
184 base::TimeTicks timestamp; | |
185 NetworkQualityEstimator::ObservationSource source; | |
186 }; | |
187 | |
188 std::vector<Observation>& observations() { return observations_; } | |
189 | |
190 // ThroughputObserver implementation: | |
191 void OnThroughputObservation( | |
192 int32_t throughput_kbps, | |
193 const base::TimeTicks& timestamp, | |
194 NetworkQualityEstimator::ObservationSource source) override { | |
195 observations_.push_back(Observation(throughput_kbps, timestamp, source)); | |
196 } | |
197 | |
198 private: | |
199 std::vector<Observation> observations_; | |
200 }; | |
201 | |
202 } // namespace | |
203 | |
204 TEST(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) { | |
205 base::HistogramTester histogram_tester; | |
206 // Enable requests to local host to be used for network quality estimation. | |
207 std::map<std::string, std::string> variation_params; | |
208 TestNetworkQualityEstimator estimator(variation_params); | |
209 | |
210 base::TimeDelta rtt; | |
211 int32_t kbps; | |
212 EXPECT_FALSE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
213 EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
214 | |
215 TestDelegate test_delegate; | |
216 TestURLRequestContext context(true); | |
217 context.set_network_quality_estimator(&estimator); | |
218 context.Init(); | |
219 | |
220 std::unique_ptr<URLRequest> request(context.CreateRequest( | |
221 estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate)); | |
222 request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME); | |
223 request->Start(); | |
224 base::RunLoop().Run(); | |
225 | |
226 // Both RTT and downstream throughput should be updated. | |
227 EXPECT_TRUE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
228 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
229 | |
230 EXPECT_TRUE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
231 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
232 | |
233 // Check UMA histograms. | |
234 histogram_tester.ExpectTotalCount("NQE.PeakKbps.Unknown", 0); | |
235 histogram_tester.ExpectTotalCount("NQE.FastestRTT.Unknown", 0); | |
236 | |
237 histogram_tester.ExpectTotalCount("NQE.RatioEstimatedToActualRTT.Unknown", 0); | |
238 | |
239 std::unique_ptr<URLRequest> request2(context.CreateRequest( | |
240 estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate)); | |
241 request2->SetLoadFlags(request2->load_flags() | LOAD_MAIN_FRAME); | |
242 request2->Start(); | |
243 base::RunLoop().Run(); | |
244 | |
245 histogram_tester.ExpectTotalCount("NQE.RTTObservations.Unknown", 1); | |
246 estimator.SimulateNetworkChangeTo( | |
247 NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1"); | |
248 histogram_tester.ExpectTotalCount("NQE.PeakKbps.Unknown", 1); | |
249 histogram_tester.ExpectTotalCount("NQE.FastestRTT.Unknown", 1); | |
250 | |
251 histogram_tester.ExpectTotalCount("NQE.RatioMedianRTT.WiFi", 0); | |
252 | |
253 histogram_tester.ExpectTotalCount("NQE.RTT.Percentile0.Unknown", 1); | |
254 histogram_tester.ExpectTotalCount("NQE.RTT.Percentile10.Unknown", 1); | |
255 histogram_tester.ExpectTotalCount("NQE.RTT.Percentile50.Unknown", 1); | |
256 histogram_tester.ExpectTotalCount("NQE.RTT.Percentile90.Unknown", 1); | |
257 histogram_tester.ExpectTotalCount("NQE.RTT.Percentile100.Unknown", 1); | |
258 | |
259 EXPECT_FALSE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
260 EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
261 | |
262 estimator.SimulateNetworkChangeTo( | |
263 NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, std::string()); | |
264 histogram_tester.ExpectTotalCount("NQE.PeakKbps.Unknown", 1); | |
265 histogram_tester.ExpectTotalCount("NQE.FastestRTT.Unknown", 1); | |
266 | |
267 EXPECT_FALSE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
268 EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
269 } | |
270 | |
271 TEST(NetworkQualityEstimatorTest, StoreObservations) { | |
272 std::map<std::string, std::string> variation_params; | |
273 TestNetworkQualityEstimator estimator(variation_params); | |
274 | |
275 base::TimeDelta rtt; | |
276 int32_t kbps; | |
277 EXPECT_FALSE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
278 EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
279 | |
280 TestDelegate test_delegate; | |
281 TestURLRequestContext context(true); | |
282 context.set_network_quality_estimator(&estimator); | |
283 context.Init(); | |
284 | |
285 // Push 10 more observations than the maximum buffer size. | |
286 for (size_t i = 0; i < estimator.kMaximumObservationsBufferSize + 10U; ++i) { | |
287 std::unique_ptr<URLRequest> request(context.CreateRequest( | |
288 estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate)); | |
289 request->Start(); | |
290 base::RunLoop().Run(); | |
291 EXPECT_TRUE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
292 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
293 } | |
294 | |
295 // Verify that the stored observations are cleared on network change. | |
296 estimator.SimulateNetworkChangeTo( | |
297 NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-2"); | |
298 EXPECT_FALSE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
299 EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
300 } | |
301 | |
302 // Verifies that the percentiles are correctly computed. All observations have | |
303 // the same timestamp. Kbps percentiles must be in decreasing order. RTT | |
304 // percentiles must be in increasing order. | |
305 TEST(NetworkQualityEstimatorTest, PercentileSameTimestamps) { | |
306 std::map<std::string, std::string> variation_params; | |
307 TestNetworkQualityEstimator estimator(variation_params); | |
308 base::TimeTicks now = base::TimeTicks::Now(); | |
309 | |
310 // Network quality should be unavailable when no observations are available. | |
311 base::TimeDelta rtt; | |
312 EXPECT_FALSE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
313 int32_t kbps; | |
314 EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
315 | |
316 // Insert samples from {1,2,3,..., 100}. First insert odd samples, then even | |
317 // samples. This helps in verifying that the order of samples does not matter. | |
318 for (int i = 1; i <= 99; i += 2) { | |
319 estimator.downstream_throughput_kbps_observations_.AddObservation( | |
320 NetworkQualityEstimator::ThroughputObservation( | |
321 i, now, NetworkQualityEstimator::URL_REQUEST)); | |
322 estimator.rtt_observations_.AddObservation( | |
323 NetworkQualityEstimator::RttObservation( | |
324 base::TimeDelta::FromMilliseconds(i), now, | |
325 NetworkQualityEstimator::URL_REQUEST)); | |
326 EXPECT_TRUE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
327 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
328 } | |
329 | |
330 for (int i = 1; i <= 99; i += 2) { | |
331 // Insert TCP observation which should not be taken into account when | |
332 // computing median RTT at HTTP layer. | |
333 estimator.rtt_observations_.AddObservation( | |
334 NetworkQualityEstimator::RttObservation( | |
335 base::TimeDelta::FromMilliseconds(10000), now, | |
336 NetworkQualityEstimator::TCP)); | |
337 | |
338 // Insert QUIC observation which should not be taken into account when | |
339 // computing median RTT at HTTP layer. | |
340 estimator.rtt_observations_.AddObservation( | |
341 NetworkQualityEstimator::RttObservation( | |
342 base::TimeDelta::FromMilliseconds(10000), now, | |
343 NetworkQualityEstimator::QUIC)); | |
344 } | |
345 | |
346 for (int i = 2; i <= 100; i += 2) { | |
347 estimator.downstream_throughput_kbps_observations_.AddObservation( | |
348 NetworkQualityEstimator::ThroughputObservation( | |
349 i, now, NetworkQualityEstimator::URL_REQUEST)); | |
350 estimator.rtt_observations_.AddObservation( | |
351 NetworkQualityEstimator::RttObservation( | |
352 base::TimeDelta::FromMilliseconds(i), now, | |
353 NetworkQualityEstimator::URL_REQUEST)); | |
354 EXPECT_TRUE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
355 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
356 } | |
357 | |
358 for (int i = 0; i <= 100; ++i) { | |
359 // Checks if the difference between the two integers is less than 1. This is | |
360 // required because computed percentiles may be slightly different from | |
361 // what is expected due to floating point computation errors and integer | |
362 // rounding off errors. | |
363 EXPECT_NEAR(estimator.GetDownlinkThroughputKbpsEstimateInternal( | |
364 base::TimeTicks(), i), | |
365 100 - i, 1); | |
366 std::vector<NetworkQualityEstimator::ObservationSource> | |
367 disallowed_observation_sources; | |
368 disallowed_observation_sources.push_back(NetworkQualityEstimator::TCP); | |
369 disallowed_observation_sources.push_back(NetworkQualityEstimator::QUIC); | |
370 EXPECT_NEAR(estimator | |
371 .GetRTTEstimateInternal(disallowed_observation_sources, | |
372 base::TimeTicks(), i) | |
373 .InMilliseconds(), | |
374 i, 1); | |
375 } | |
376 | |
377 EXPECT_TRUE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
378 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
379 } | |
380 | |
381 // Verifies that the percentiles are correctly computed. Observations have | |
382 // different timestamps with half the observations being very old and the rest | |
383 // of them being very recent. Percentiles should factor in recent observations | |
384 // much more heavily than older samples. Kbps percentiles must be in decreasing | |
385 // order. RTT percentiles must be in increasing order. | |
386 TEST(NetworkQualityEstimatorTest, PercentileDifferentTimestamps) { | |
387 std::map<std::string, std::string> variation_params; | |
388 TestNetworkQualityEstimator estimator(variation_params); | |
389 base::TimeTicks now = base::TimeTicks::Now(); | |
390 base::TimeTicks very_old = now - base::TimeDelta::FromDays(365); | |
391 | |
392 // First 50 samples have very old timestamp. | |
393 for (int i = 1; i <= 50; ++i) { | |
394 estimator.downstream_throughput_kbps_observations_.AddObservation( | |
395 NetworkQualityEstimator::ThroughputObservation( | |
396 i, very_old, NetworkQualityEstimator::URL_REQUEST)); | |
397 estimator.rtt_observations_.AddObservation( | |
398 NetworkQualityEstimator::RttObservation( | |
399 base::TimeDelta::FromMilliseconds(i), very_old, | |
400 NetworkQualityEstimator::URL_REQUEST)); | |
401 } | |
402 | |
403 // Next 50 (i.e., from 51 to 100) have recent timestamp. | |
404 for (int i = 51; i <= 100; ++i) { | |
405 estimator.downstream_throughput_kbps_observations_.AddObservation( | |
406 NetworkQualityEstimator::ThroughputObservation( | |
407 i, now, NetworkQualityEstimator::URL_REQUEST)); | |
408 | |
409 // Insert TCP observation which should not be taken into account when | |
410 // computing median RTT at HTTP layer. | |
411 estimator.rtt_observations_.AddObservation( | |
412 NetworkQualityEstimator::RttObservation( | |
413 base::TimeDelta::FromMilliseconds(10000), now, | |
414 NetworkQualityEstimator::TCP)); | |
415 | |
416 estimator.rtt_observations_.AddObservation( | |
417 NetworkQualityEstimator::RttObservation( | |
418 base::TimeDelta::FromMilliseconds(i), now, | |
419 NetworkQualityEstimator::URL_REQUEST)); | |
420 } | |
421 | |
422 std::vector<NetworkQualityEstimator::ObservationSource> | |
423 disallowed_observation_sources; | |
424 disallowed_observation_sources.push_back(NetworkQualityEstimator::TCP); | |
425 disallowed_observation_sources.push_back(NetworkQualityEstimator::QUIC); | |
426 | |
427 // Older samples have very little weight. So, all percentiles are >= 51 | |
428 // (lowest value among recent observations). | |
429 for (int i = 1; i < 100; ++i) { | |
430 // Checks if the difference between the two integers is less than 1. This is | |
431 // required because computed percentiles may be slightly different from | |
432 // what is expected due to floating point computation errors and integer | |
433 // rounding off errors. | |
434 EXPECT_NEAR(estimator.GetDownlinkThroughputKbpsEstimateInternal( | |
435 base::TimeTicks(), i), | |
436 51 + 0.49 * (100 - i), 1); | |
437 EXPECT_NEAR(estimator | |
438 .GetRTTEstimateInternal(disallowed_observation_sources, | |
439 base::TimeTicks(), i) | |
440 .InMilliseconds(), | |
441 51 + 0.49 * i, 1); | |
442 } | |
443 } | |
444 | |
445 // This test notifies NetworkQualityEstimator of received data. Next, | |
446 // throughput and RTT percentiles are checked for correctness by doing simple | |
447 // verifications. | |
448 TEST(NetworkQualityEstimatorTest, ComputedPercentiles) { | |
449 std::map<std::string, std::string> variation_params; | |
450 TestNetworkQualityEstimator estimator(variation_params); | |
451 | |
452 std::vector<NetworkQualityEstimator::ObservationSource> | |
453 disallowed_observation_sources; | |
454 disallowed_observation_sources.push_back(NetworkQualityEstimator::TCP); | |
455 disallowed_observation_sources.push_back(NetworkQualityEstimator::QUIC); | |
456 | |
457 EXPECT_EQ(NetworkQualityEstimator::InvalidRTT(), | |
458 estimator.GetRTTEstimateInternal(disallowed_observation_sources, | |
459 base::TimeTicks(), 100)); | |
460 EXPECT_EQ(NetworkQualityEstimator::kInvalidThroughput, | |
461 estimator.GetDownlinkThroughputKbpsEstimateInternal( | |
462 base::TimeTicks(), 100)); | |
463 | |
464 TestDelegate test_delegate; | |
465 TestURLRequestContext context(true); | |
466 context.set_network_quality_estimator(&estimator); | |
467 context.Init(); | |
468 | |
469 // Number of observations are more than the maximum buffer size. | |
470 for (size_t i = 0; i < estimator.kMaximumObservationsBufferSize + 100U; ++i) { | |
471 std::unique_ptr<URLRequest> request(context.CreateRequest( | |
472 estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate)); | |
473 request->Start(); | |
474 base::RunLoop().Run(); | |
475 } | |
476 | |
477 // Verify the percentiles through simple tests. | |
478 for (int i = 0; i <= 100; ++i) { | |
479 EXPECT_GT(estimator.GetDownlinkThroughputKbpsEstimateInternal( | |
480 base::TimeTicks(), i), | |
481 0); | |
482 EXPECT_LT(estimator.GetRTTEstimateInternal(disallowed_observation_sources, | |
483 base::TimeTicks(), i), | |
484 base::TimeDelta::Max()); | |
485 | |
486 if (i != 0) { | |
487 // Throughput percentiles are in decreasing order. | |
488 EXPECT_LE(estimator.GetDownlinkThroughputKbpsEstimateInternal( | |
489 base::TimeTicks(), i), | |
490 estimator.GetDownlinkThroughputKbpsEstimateInternal( | |
491 base::TimeTicks(), i - 1)); | |
492 | |
493 // RTT percentiles are in increasing order. | |
494 EXPECT_GE(estimator.GetRTTEstimateInternal(disallowed_observation_sources, | |
495 base::TimeTicks(), i), | |
496 estimator.GetRTTEstimateInternal(disallowed_observation_sources, | |
497 base::TimeTicks(), i - 1)); | |
498 } | |
499 } | |
500 } | |
501 | |
502 TEST(NetworkQualityEstimatorTest, ObtainOperatingParams) { | |
503 std::map<std::string, std::string> variation_params; | |
504 variation_params["Unknown.DefaultMedianKbps"] = "100"; | |
505 variation_params["WiFi.DefaultMedianKbps"] = "200"; | |
506 variation_params["2G.DefaultMedianKbps"] = "300"; | |
507 | |
508 variation_params["Unknown.DefaultMedianRTTMsec"] = "1000"; | |
509 variation_params["WiFi.DefaultMedianRTTMsec"] = "2000"; | |
510 // Negative variation value should not be used. | |
511 variation_params["2G.DefaultMedianRTTMsec"] = "-5"; | |
512 | |
513 TestNetworkQualityEstimator estimator(variation_params); | |
514 | |
515 base::TimeDelta rtt; | |
516 EXPECT_TRUE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
517 int32_t kbps; | |
518 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
519 | |
520 EXPECT_EQ(100, kbps); | |
521 EXPECT_EQ(base::TimeDelta::FromMilliseconds(1000), rtt); | |
522 | |
523 // Simulate network change to Wi-Fi. | |
524 estimator.SimulateNetworkChangeTo( | |
525 NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1"); | |
526 | |
527 EXPECT_TRUE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
528 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
529 EXPECT_EQ(200, kbps); | |
530 EXPECT_EQ(base::TimeDelta::FromMilliseconds(2000), rtt); | |
531 | |
532 // Peak network quality should not be affected by the network quality | |
533 // estimator field trial. | |
534 EXPECT_EQ(NetworkQualityEstimator::InvalidRTT(), | |
535 estimator.peak_network_quality_.rtt()); | |
536 EXPECT_EQ(NetworkQualityEstimator::kInvalidThroughput, | |
537 estimator.peak_network_quality_.downstream_throughput_kbps()); | |
538 | |
539 // Simulate network change to 2G. Only the Kbps default estimate should be | |
540 // available. | |
541 estimator.SimulateNetworkChangeTo( | |
542 NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-2"); | |
543 | |
544 EXPECT_FALSE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
545 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
546 EXPECT_EQ(300, kbps); | |
547 | |
548 // Simulate network change to 3G. Default estimates should be unavailable. | |
549 estimator.SimulateNetworkChangeTo( | |
550 NetworkChangeNotifier::ConnectionType::CONNECTION_3G, "test-3"); | |
551 | |
552 EXPECT_FALSE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
553 EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
554 } | |
555 | |
556 // Tests that |GetEffectiveConnectionType| returns correct connection type when | |
557 // no variation params are specified. | |
558 TEST(NetworkQualityEstimatorTest, ObtainThresholdsNone) { | |
559 std::map<std::string, std::string> variation_params; | |
560 | |
561 TestNetworkQualityEstimator estimator(variation_params); | |
562 | |
563 const struct { | |
564 int32_t rtt_msec; | |
565 NetworkQualityEstimator::EffectiveConnectionType expected_conn_type; | |
566 } tests[] = { | |
567 {5000, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_BROADBAND}, | |
568 {20, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_BROADBAND}, | |
569 }; | |
570 | |
571 for (const auto& test : tests) { | |
572 estimator.set_url_rtt(base::TimeDelta::FromMilliseconds(test.rtt_msec)); | |
573 EXPECT_EQ(test.expected_conn_type, estimator.GetEffectiveConnectionType()); | |
574 } | |
575 } | |
576 | |
577 // Tests that |GetEffectiveConnectionType| returns correct connection type when | |
578 // only RTT thresholds are specified in the variation params. | |
579 TEST(NetworkQualityEstimatorTest, ObtainThresholdsOnlyRTT) { | |
580 std::map<std::string, std::string> variation_params; | |
581 | |
582 variation_params["Offline.ThresholdMedianURLRTTMsec"] = "4000"; | |
583 variation_params["Slow2G.ThresholdMedianURLRTTMsec"] = "2000"; | |
584 variation_params["2G.ThresholdMedianURLRTTMsec"] = "1000"; | |
585 variation_params["3G.ThresholdMedianURLRTTMsec"] = "500"; | |
586 variation_params["4G.ThresholdMedianURLRTTMsec"] = "300"; | |
587 variation_params["Broadband.ThresholdMedianURLRTTMsec"] = "100"; | |
588 | |
589 TestNetworkQualityEstimator estimator(variation_params); | |
590 | |
591 const struct { | |
592 int32_t rtt_msec; | |
593 NetworkQualityEstimator::EffectiveConnectionType expected_conn_type; | |
594 } tests[] = { | |
595 {5000, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_OFFLINE}, | |
596 {4000, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_OFFLINE}, | |
597 {3000, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G}, | |
598 {2000, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G}, | |
599 {1500, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G}, | |
600 {1000, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G}, | |
601 {700, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_3G}, | |
602 {500, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_3G}, | |
603 {400, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_4G}, | |
604 {300, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_4G}, | |
605 {200, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_BROADBAND}, | |
606 {100, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_BROADBAND}, | |
607 {20, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_BROADBAND}, | |
608 }; | |
609 | |
610 for (const auto& test : tests) { | |
611 estimator.set_url_rtt(base::TimeDelta::FromMilliseconds(test.rtt_msec)); | |
612 EXPECT_EQ(test.expected_conn_type, estimator.GetEffectiveConnectionType()); | |
613 } | |
614 } | |
615 | |
616 // Tests that |GetEffectiveConnectionType| returns correct connection type when | |
617 // both RTT and throughput thresholds are specified in the variation params. | |
618 TEST(NetworkQualityEstimatorTest, ObtainThresholdsRTTandThroughput) { | |
619 std::map<std::string, std::string> variation_params; | |
620 | |
621 variation_params["Offline.ThresholdMedianURLRTTMsec"] = "4000"; | |
622 variation_params["Slow2G.ThresholdMedianURLRTTMsec"] = "2000"; | |
623 variation_params["2G.ThresholdMedianURLRTTMsec"] = "1000"; | |
624 variation_params["3G.ThresholdMedianURLRTTMsec"] = "500"; | |
625 variation_params["4G.ThresholdMedianURLRTTMsec"] = "300"; | |
626 variation_params["Broadband.ThresholdMedianURLRTTMsec"] = "100"; | |
627 | |
628 variation_params["Offline.ThresholdMedianKbps"] = "10"; | |
629 variation_params["Slow2G.ThresholdMedianKbps"] = "100"; | |
630 variation_params["2G.ThresholdMedianKbps"] = "300"; | |
631 variation_params["3G.ThresholdMedianKbps"] = "500"; | |
632 variation_params["4G.ThresholdMedianKbps"] = "1000"; | |
633 variation_params["Broadband.ThresholdMedianKbps"] = "2000"; | |
634 | |
635 TestNetworkQualityEstimator estimator(variation_params); | |
636 | |
637 const struct { | |
638 int32_t rtt_msec; | |
639 int32_t downlink_throughput_kbps; | |
640 NetworkQualityEstimator::EffectiveConnectionType expected_conn_type; | |
641 } tests[] = { | |
642 // Set RTT to a very low value to observe the effect of throughput. | |
643 // Throughout is the bottleneck. | |
644 {1, 5, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_OFFLINE}, | |
645 {1, 10, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_OFFLINE}, | |
646 {1, 50, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G}, | |
647 {1, 100, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G}, | |
648 {1, 150, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G}, | |
649 {1, 300, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_2G}, | |
650 {1, 400, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_3G}, | |
651 {1, 500, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_3G}, | |
652 {1, 700, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_4G}, | |
653 {1, 1000, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_4G}, | |
654 {1, 1500, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_BROADBAND}, | |
655 {1, 2500, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_BROADBAND}, | |
656 // Set both RTT and throughput. RTT is the bottleneck. | |
657 {3000, 25000, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G}, | |
658 {700, 25000, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_3G}, | |
659 // Set throughput to an invalid value. | |
660 {3000, 0, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_SLOW_2G}, | |
661 {700, 0, NetworkQualityEstimator::EFFECTIVE_CONNECTION_TYPE_3G}, | |
662 }; | |
663 | |
664 for (const auto& test : tests) { | |
665 estimator.set_url_rtt(base::TimeDelta::FromMilliseconds(test.rtt_msec)); | |
666 estimator.set_downlink_throughput_kbps(test.downlink_throughput_kbps); | |
667 EXPECT_EQ(test.expected_conn_type, estimator.GetEffectiveConnectionType()); | |
668 } | |
669 } | |
670 | |
671 // Tests if |weight_multiplier_per_second_| is set to correct value for various | |
672 // values of half life parameter. | |
673 TEST(NetworkQualityEstimatorTest, HalfLifeParam) { | |
674 std::map<std::string, std::string> variation_params; | |
675 | |
676 const struct { | |
677 std::string description; | |
678 std::string variation_params_value; | |
679 double expected_weight_multiplier; | |
680 } tests[] = { | |
681 {"Half life parameter is not set, default value should be used", | |
682 std::string(), 0.988}, | |
683 {"Half life parameter is set to negative, default value should be used", | |
684 "-100", 0.988}, | |
685 {"Half life parameter is set to zero, default value should be used", "0", | |
686 0.988}, | |
687 {"Half life parameter is set correctly", "10", 0.933}, | |
688 }; | |
689 | |
690 for (const auto& test : tests) { | |
691 variation_params["HalfLifeSeconds"] = test.variation_params_value; | |
692 TestNetworkQualityEstimator estimator(variation_params); | |
693 EXPECT_NEAR(test.expected_weight_multiplier, | |
694 estimator.weight_multiplier_per_second_, 0.001) | |
695 << test.description; | |
696 } | |
697 } | |
698 | |
699 // Test if the network estimates are cached when network change notification | |
700 // is invoked. | |
701 TEST(NetworkQualityEstimatorTest, TestCaching) { | |
702 std::map<std::string, std::string> variation_params; | |
703 TestNetworkQualityEstimator estimator(variation_params); | |
704 size_t expected_cache_size = 0; | |
705 EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size()); | |
706 | |
707 // Cache entry will not be added for (NONE, ""). | |
708 estimator.downstream_throughput_kbps_observations_.AddObservation( | |
709 NetworkQualityEstimator::ThroughputObservation( | |
710 1, base::TimeTicks::Now(), NetworkQualityEstimator::URL_REQUEST)); | |
711 estimator.rtt_observations_.AddObservation( | |
712 NetworkQualityEstimator::RttObservation( | |
713 base::TimeDelta::FromMilliseconds(1000), base::TimeTicks::Now(), | |
714 NetworkQualityEstimator::URL_REQUEST)); | |
715 estimator.SimulateNetworkChangeTo( | |
716 NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-1"); | |
717 EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size()); | |
718 | |
719 // Entry will be added for (2G, "test1"). | |
720 // Also, set the network quality for (2G, "test1") so that it is stored in | |
721 // the cache. | |
722 estimator.downstream_throughput_kbps_observations_.AddObservation( | |
723 NetworkQualityEstimator::ThroughputObservation( | |
724 1, base::TimeTicks::Now(), NetworkQualityEstimator::URL_REQUEST)); | |
725 estimator.rtt_observations_.AddObservation( | |
726 NetworkQualityEstimator::RttObservation( | |
727 base::TimeDelta::FromMilliseconds(1000), base::TimeTicks::Now(), | |
728 NetworkQualityEstimator::URL_REQUEST)); | |
729 | |
730 estimator.SimulateNetworkChangeTo( | |
731 NetworkChangeNotifier::ConnectionType::CONNECTION_3G, "test-1"); | |
732 ++expected_cache_size; | |
733 EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size()); | |
734 | |
735 // Entry will be added for (3G, "test1"). | |
736 // Also, set the network quality for (3G, "test1") so that it is stored in | |
737 // the cache. | |
738 estimator.downstream_throughput_kbps_observations_.AddObservation( | |
739 NetworkQualityEstimator::ThroughputObservation( | |
740 2, base::TimeTicks::Now(), NetworkQualityEstimator::URL_REQUEST)); | |
741 estimator.rtt_observations_.AddObservation( | |
742 NetworkQualityEstimator::RttObservation( | |
743 base::TimeDelta::FromMilliseconds(500), base::TimeTicks::Now(), | |
744 NetworkQualityEstimator::URL_REQUEST)); | |
745 estimator.SimulateNetworkChangeTo( | |
746 NetworkChangeNotifier::ConnectionType::CONNECTION_3G, "test-2"); | |
747 ++expected_cache_size; | |
748 EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size()); | |
749 | |
750 // Entry will not be added for (3G, "test2"). | |
751 estimator.SimulateNetworkChangeTo( | |
752 NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-1"); | |
753 EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size()); | |
754 | |
755 // Read the network quality for (2G, "test-1"). | |
756 EXPECT_TRUE(estimator.ReadCachedNetworkQualityEstimate()); | |
757 | |
758 base::TimeDelta rtt; | |
759 int32_t kbps; | |
760 EXPECT_TRUE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
761 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
762 EXPECT_EQ(1, kbps); | |
763 EXPECT_EQ(base::TimeDelta::FromMilliseconds(1000), rtt); | |
764 // No new entry should be added for (2G, "test-1") since it already exists | |
765 // in the cache. | |
766 estimator.SimulateNetworkChangeTo( | |
767 NetworkChangeNotifier::ConnectionType::CONNECTION_3G, "test-1"); | |
768 EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size()); | |
769 | |
770 // Read the network quality for (3G, "test-1"). | |
771 EXPECT_TRUE(estimator.ReadCachedNetworkQualityEstimate()); | |
772 EXPECT_TRUE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
773 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
774 EXPECT_EQ(2, kbps); | |
775 EXPECT_EQ(base::TimeDelta::FromMilliseconds(500), rtt); | |
776 // No new entry should be added for (3G, "test1") since it already exists | |
777 // in the cache. | |
778 estimator.SimulateNetworkChangeTo( | |
779 NetworkChangeNotifier::ConnectionType::CONNECTION_3G, "test-2"); | |
780 EXPECT_EQ(expected_cache_size, estimator.cached_network_qualities_.size()); | |
781 | |
782 // Reading quality of (3G, "test-2") should return false. | |
783 EXPECT_FALSE(estimator.ReadCachedNetworkQualityEstimate()); | |
784 | |
785 // Reading quality of (2G, "test-3") should return false. | |
786 estimator.SimulateNetworkChangeTo( | |
787 NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-3"); | |
788 EXPECT_FALSE(estimator.ReadCachedNetworkQualityEstimate()); | |
789 } | |
790 | |
791 // Tests if the cache size remains bounded. Also, ensure that the cache is | |
792 // LRU. | |
793 TEST(NetworkQualityEstimatorTest, TestLRUCacheMaximumSize) { | |
794 std::map<std::string, std::string> variation_params; | |
795 TestNetworkQualityEstimator estimator(variation_params); | |
796 estimator.SimulateNetworkChangeTo( | |
797 NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, std::string()); | |
798 EXPECT_EQ(0U, estimator.cached_network_qualities_.size()); | |
799 | |
800 // Add 100 more networks than the maximum size of the cache. | |
801 size_t network_count = | |
802 NetworkQualityEstimator::kMaximumNetworkQualityCacheSize + 100; | |
803 | |
804 base::TimeTicks update_time_of_network_100; | |
805 for (size_t i = 0; i < network_count; ++i) { | |
806 estimator.downstream_throughput_kbps_observations_.AddObservation( | |
807 NetworkQualityEstimator::ThroughputObservation( | |
808 2, base::TimeTicks::Now(), NetworkQualityEstimator::URL_REQUEST)); | |
809 estimator.rtt_observations_.AddObservation( | |
810 NetworkQualityEstimator::RttObservation( | |
811 base::TimeDelta::FromMilliseconds(500), base::TimeTicks::Now(), | |
812 NetworkQualityEstimator::URL_REQUEST)); | |
813 | |
814 if (i == 100) | |
815 update_time_of_network_100 = base::TimeTicks::Now(); | |
816 | |
817 estimator.SimulateNetworkChangeTo( | |
818 NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, | |
819 base::SizeTToString(i)); | |
820 if (i < NetworkQualityEstimator::kMaximumNetworkQualityCacheSize) | |
821 EXPECT_EQ(i, estimator.cached_network_qualities_.size()); | |
822 EXPECT_LE(estimator.cached_network_qualities_.size(), | |
823 static_cast<size_t>( | |
824 NetworkQualityEstimator::kMaximumNetworkQualityCacheSize)); | |
825 } | |
826 // One more call so that the last network is also written to cache. | |
827 estimator.downstream_throughput_kbps_observations_.AddObservation( | |
828 NetworkQualityEstimator::ThroughputObservation( | |
829 2, base::TimeTicks::Now(), NetworkQualityEstimator::URL_REQUEST)); | |
830 estimator.rtt_observations_.AddObservation( | |
831 NetworkQualityEstimator::RttObservation( | |
832 base::TimeDelta::FromMilliseconds(500), base::TimeTicks::Now(), | |
833 NetworkQualityEstimator::URL_REQUEST)); | |
834 estimator.SimulateNetworkChangeTo( | |
835 NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, | |
836 base::SizeTToString(network_count - 1)); | |
837 EXPECT_EQ(static_cast<size_t>( | |
838 NetworkQualityEstimator::kMaximumNetworkQualityCacheSize), | |
839 estimator.cached_network_qualities_.size()); | |
840 | |
841 // Test that the cache is LRU by examining its contents. Networks in cache | |
842 // must all be newer than the 100th network. | |
843 for (NetworkQualityEstimator::CachedNetworkQualities::iterator it = | |
844 estimator.cached_network_qualities_.begin(); | |
845 it != estimator.cached_network_qualities_.end(); ++it) { | |
846 EXPECT_GE((it->second).last_update_time_, update_time_of_network_100); | |
847 } | |
848 } | |
849 | |
850 TEST(NetworkQualityEstimatorTest, TestGetMedianRTTSince) { | |
851 std::map<std::string, std::string> variation_params; | |
852 TestNetworkQualityEstimator estimator(variation_params); | |
853 base::TimeTicks now = base::TimeTicks::Now(); | |
854 base::TimeTicks old = now - base::TimeDelta::FromMilliseconds(1); | |
855 ASSERT_NE(old, now); | |
856 | |
857 // First sample has very old timestamp. | |
858 estimator.downstream_throughput_kbps_observations_.AddObservation( | |
859 NetworkQualityEstimator::ThroughputObservation( | |
860 1, old, NetworkQualityEstimator::URL_REQUEST)); | |
861 estimator.rtt_observations_.AddObservation( | |
862 NetworkQualityEstimator::RttObservation( | |
863 base::TimeDelta::FromMilliseconds(1), old, | |
864 NetworkQualityEstimator::URL_REQUEST)); | |
865 | |
866 estimator.downstream_throughput_kbps_observations_.AddObservation( | |
867 NetworkQualityEstimator::ThroughputObservation( | |
868 100, now, NetworkQualityEstimator::URL_REQUEST)); | |
869 estimator.rtt_observations_.AddObservation( | |
870 NetworkQualityEstimator::RttObservation( | |
871 base::TimeDelta::FromMilliseconds(100), now, | |
872 NetworkQualityEstimator::URL_REQUEST)); | |
873 | |
874 const struct { | |
875 base::TimeTicks start_timestamp; | |
876 bool expect_network_quality_available; | |
877 base::TimeDelta expected_url_request_rtt; | |
878 int32_t expected_downstream_throughput; | |
879 } tests[] = { | |
880 {now + base::TimeDelta::FromSeconds(10), false, | |
881 base::TimeDelta::FromMilliseconds(0), 0}, | |
882 {now, true, base::TimeDelta::FromMilliseconds(100), 100}, | |
883 {now - base::TimeDelta::FromMicroseconds(500), true, | |
884 base::TimeDelta::FromMilliseconds(100), 100}, | |
885 | |
886 }; | |
887 | |
888 for (const auto& test : tests) { | |
889 base::TimeDelta url_request_rtt; | |
890 int32_t downstream_throughput_kbps; | |
891 EXPECT_EQ(test.expect_network_quality_available, | |
892 estimator.GetRecentURLRequestRTTMedian(test.start_timestamp, | |
893 &url_request_rtt)); | |
894 EXPECT_EQ(test.expect_network_quality_available, | |
895 estimator.GetRecentMedianDownlinkThroughputKbps( | |
896 test.start_timestamp, &downstream_throughput_kbps)); | |
897 | |
898 if (test.expect_network_quality_available) { | |
899 EXPECT_EQ(test.expected_url_request_rtt, url_request_rtt); | |
900 EXPECT_EQ(test.expected_downstream_throughput, | |
901 downstream_throughput_kbps); | |
902 } | |
903 } | |
904 } | |
905 | |
906 // An external estimate provider that does not have a valid RTT or throughput | |
907 // estimate. | |
908 class InvalidExternalEstimateProvider : public ExternalEstimateProvider { | |
909 public: | |
910 InvalidExternalEstimateProvider() : get_rtt_count_(0) {} | |
911 ~InvalidExternalEstimateProvider() override {} | |
912 | |
913 // ExternalEstimateProvider implementation: | |
914 bool GetRTT(base::TimeDelta* rtt) const override { | |
915 DCHECK(rtt); | |
916 get_rtt_count_++; | |
917 return false; | |
918 } | |
919 | |
920 // ExternalEstimateProvider implementation: | |
921 bool GetDownstreamThroughputKbps( | |
922 int32_t* downstream_throughput_kbps) const override { | |
923 DCHECK(downstream_throughput_kbps); | |
924 return false; | |
925 } | |
926 | |
927 // ExternalEstimateProvider implementation: | |
928 bool GetUpstreamThroughputKbps( | |
929 int32_t* upstream_throughput_kbps) const override { | |
930 // NetworkQualityEstimator does not support upstream throughput. | |
931 ADD_FAILURE(); | |
932 return false; | |
933 } | |
934 | |
935 // ExternalEstimateProvider implementation: | |
936 bool GetTimeSinceLastUpdate( | |
937 base::TimeDelta* time_since_last_update) const override { | |
938 *time_since_last_update = base::TimeDelta::FromMilliseconds(1); | |
939 return true; | |
940 } | |
941 | |
942 // ExternalEstimateProvider implementation: | |
943 void SetUpdatedEstimateDelegate(UpdatedEstimateDelegate* delegate) override {} | |
944 | |
945 // ExternalEstimateProvider implementation: | |
946 void Update() const override {} | |
947 | |
948 size_t get_rtt_count() const { return get_rtt_count_; } | |
949 | |
950 private: | |
951 // Keeps track of number of times different functions were called. | |
952 mutable size_t get_rtt_count_; | |
953 | |
954 DISALLOW_COPY_AND_ASSIGN(InvalidExternalEstimateProvider); | |
955 }; | |
956 | |
957 // Tests if the RTT value from external estimate provider is discarded if the | |
958 // external estimate provider is invalid. | |
959 TEST(NetworkQualityEstimatorTest, InvalidExternalEstimateProvider) { | |
960 base::HistogramTester histogram_tester; | |
961 InvalidExternalEstimateProvider* invalid_external_estimate_provider = | |
962 new InvalidExternalEstimateProvider(); | |
963 std::unique_ptr<ExternalEstimateProvider> external_estimate_provider( | |
964 invalid_external_estimate_provider); | |
965 | |
966 TestNetworkQualityEstimator estimator(std::map<std::string, std::string>(), | |
967 std::move(external_estimate_provider)); | |
968 | |
969 base::TimeDelta rtt; | |
970 int32_t kbps; | |
971 EXPECT_EQ(1U, invalid_external_estimate_provider->get_rtt_count()); | |
972 EXPECT_FALSE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
973 EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
974 histogram_tester.ExpectTotalCount("NQE.ExternalEstimateProviderStatus", 3); | |
975 | |
976 histogram_tester.ExpectBucketCount( | |
977 "NQE.ExternalEstimateProviderStatus", | |
978 1 /* EXTERNAL_ESTIMATE_PROVIDER_STATUS_AVAILABLE */, 1); | |
979 histogram_tester.ExpectBucketCount( | |
980 "NQE.ExternalEstimateProviderStatus", | |
981 2 /* EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERIED */, 1); | |
982 histogram_tester.ExpectBucketCount( | |
983 "NQE.ExternalEstimateProviderStatus", | |
984 3 /* EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERY_SUCCESSFUL */, 1); | |
985 histogram_tester.ExpectTotalCount("NQE.ExternalEstimateProvider.RTT", 0); | |
986 histogram_tester.ExpectTotalCount( | |
987 "NQE.ExternalEstimateProvider.DownlinkBandwidth", 0); | |
988 } | |
989 | |
990 class TestExternalEstimateProvider : public ExternalEstimateProvider { | |
991 public: | |
992 TestExternalEstimateProvider(base::TimeDelta rtt, | |
993 int32_t downstream_throughput_kbps) | |
994 : rtt_(rtt), | |
995 downstream_throughput_kbps_(downstream_throughput_kbps), | |
996 time_since_last_update_(base::TimeDelta::FromSeconds(1)), | |
997 get_time_since_last_update_count_(0), | |
998 get_rtt_count_(0), | |
999 get_downstream_throughput_kbps_count_(0), | |
1000 update_count_(0) {} | |
1001 ~TestExternalEstimateProvider() override {} | |
1002 | |
1003 // ExternalEstimateProvider implementation: | |
1004 bool GetRTT(base::TimeDelta* rtt) const override { | |
1005 *rtt = rtt_; | |
1006 get_rtt_count_++; | |
1007 return true; | |
1008 } | |
1009 | |
1010 // ExternalEstimateProvider implementation: | |
1011 bool GetDownstreamThroughputKbps( | |
1012 int32_t* downstream_throughput_kbps) const override { | |
1013 *downstream_throughput_kbps = downstream_throughput_kbps_; | |
1014 get_downstream_throughput_kbps_count_++; | |
1015 return true; | |
1016 } | |
1017 | |
1018 // ExternalEstimateProvider implementation: | |
1019 bool GetUpstreamThroughputKbps( | |
1020 int32_t* upstream_throughput_kbps) const override { | |
1021 // NetworkQualityEstimator does not support upstream throughput. | |
1022 ADD_FAILURE(); | |
1023 return false; | |
1024 } | |
1025 | |
1026 // ExternalEstimateProvider implementation: | |
1027 bool GetTimeSinceLastUpdate( | |
1028 base::TimeDelta* time_since_last_update) const override { | |
1029 *time_since_last_update = time_since_last_update_; | |
1030 get_time_since_last_update_count_++; | |
1031 return true; | |
1032 } | |
1033 | |
1034 // ExternalEstimateProvider implementation: | |
1035 void SetUpdatedEstimateDelegate(UpdatedEstimateDelegate* delegate) override {} | |
1036 | |
1037 // ExternalEstimateProvider implementation: | |
1038 void Update() const override { update_count_++; } | |
1039 | |
1040 void set_time_since_last_update(base::TimeDelta time_since_last_update) { | |
1041 time_since_last_update_ = time_since_last_update; | |
1042 } | |
1043 | |
1044 size_t get_time_since_last_update_count() const { | |
1045 return get_time_since_last_update_count_; | |
1046 } | |
1047 size_t get_rtt_count() const { return get_rtt_count_; } | |
1048 size_t get_downstream_throughput_kbps_count() const { | |
1049 return get_downstream_throughput_kbps_count_; | |
1050 } | |
1051 size_t update_count() const { return update_count_; } | |
1052 | |
1053 private: | |
1054 // RTT and downstream throughput estimates. | |
1055 const base::TimeDelta rtt_; | |
1056 const int32_t downstream_throughput_kbps_; | |
1057 | |
1058 base::TimeDelta time_since_last_update_; | |
1059 | |
1060 // Keeps track of number of times different functions were called. | |
1061 mutable size_t get_time_since_last_update_count_; | |
1062 mutable size_t get_rtt_count_; | |
1063 mutable size_t get_downstream_throughput_kbps_count_; | |
1064 mutable size_t update_count_; | |
1065 | |
1066 DISALLOW_COPY_AND_ASSIGN(TestExternalEstimateProvider); | |
1067 }; | |
1068 | |
1069 // Tests if the external estimate provider is called in the constructor and | |
1070 // on network change notification. | |
1071 TEST(NetworkQualityEstimatorTest, TestExternalEstimateProvider) { | |
1072 base::HistogramTester histogram_tester; | |
1073 TestExternalEstimateProvider* test_external_estimate_provider = | |
1074 new TestExternalEstimateProvider(base::TimeDelta::FromMilliseconds(1), | |
1075 100); | |
1076 std::unique_ptr<ExternalEstimateProvider> external_estimate_provider( | |
1077 test_external_estimate_provider); | |
1078 std::map<std::string, std::string> variation_params; | |
1079 TestNetworkQualityEstimator estimator(variation_params, | |
1080 std::move(external_estimate_provider)); | |
1081 | |
1082 base::TimeDelta rtt; | |
1083 int32_t kbps; | |
1084 EXPECT_TRUE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
1085 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
1086 | |
1087 histogram_tester.ExpectTotalCount("NQE.ExternalEstimateProviderStatus", 5); | |
1088 | |
1089 histogram_tester.ExpectBucketCount( | |
1090 "NQE.ExternalEstimateProviderStatus", | |
1091 1 /* EXTERNAL_ESTIMATE_PROVIDER_STATUS_AVAILABLE */, 1); | |
1092 histogram_tester.ExpectBucketCount( | |
1093 "NQE.ExternalEstimateProviderStatus", | |
1094 2 /* EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERIED */, 1); | |
1095 histogram_tester.ExpectBucketCount( | |
1096 "NQE.ExternalEstimateProviderStatus", | |
1097 3 /* EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERY_SUCCESSFUL */, 1); | |
1098 histogram_tester.ExpectBucketCount( | |
1099 "NQE.ExternalEstimateProviderStatus", | |
1100 5 /* EXTERNAL_ESTIMATE_PROVIDER_STATUS_RTT_AVAILABLE */, 1); | |
1101 histogram_tester.ExpectBucketCount( | |
1102 "NQE.ExternalEstimateProviderStatus", | |
1103 6 /* EXTERNAL_ESTIMATE_PROVIDER_STATUS_DOWNLINK_BANDWIDTH_AVAILABLE */, | |
1104 1); | |
1105 histogram_tester.ExpectTotalCount("NQE.ExternalEstimateProvider.RTT", 1); | |
1106 histogram_tester.ExpectBucketCount("NQE.ExternalEstimateProvider.RTT", 1, 1); | |
1107 | |
1108 histogram_tester.ExpectTotalCount( | |
1109 "NQE.ExternalEstimateProvider.DownlinkBandwidth", 1); | |
1110 histogram_tester.ExpectBucketCount( | |
1111 "NQE.ExternalEstimateProvider.DownlinkBandwidth", 100, 1); | |
1112 | |
1113 EXPECT_EQ( | |
1114 1U, test_external_estimate_provider->get_time_since_last_update_count()); | |
1115 EXPECT_EQ(1U, test_external_estimate_provider->get_rtt_count()); | |
1116 EXPECT_EQ( | |
1117 1U, | |
1118 test_external_estimate_provider->get_downstream_throughput_kbps_count()); | |
1119 | |
1120 // Change network type to WiFi. Number of queries to External estimate | |
1121 // provider must increment. | |
1122 estimator.SimulateNetworkChangeTo( | |
1123 NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1"); | |
1124 EXPECT_TRUE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
1125 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
1126 EXPECT_EQ( | |
1127 2U, test_external_estimate_provider->get_time_since_last_update_count()); | |
1128 EXPECT_EQ(2U, test_external_estimate_provider->get_rtt_count()); | |
1129 EXPECT_EQ( | |
1130 2U, | |
1131 test_external_estimate_provider->get_downstream_throughput_kbps_count()); | |
1132 | |
1133 // Change network type to 2G. Number of queries to External estimate provider | |
1134 // must increment. | |
1135 estimator.SimulateNetworkChangeTo( | |
1136 NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-1"); | |
1137 EXPECT_EQ( | |
1138 3U, test_external_estimate_provider->get_time_since_last_update_count()); | |
1139 EXPECT_EQ(3U, test_external_estimate_provider->get_rtt_count()); | |
1140 EXPECT_EQ( | |
1141 3U, | |
1142 test_external_estimate_provider->get_downstream_throughput_kbps_count()); | |
1143 | |
1144 // Set the external estimate as old. Network Quality estimator should request | |
1145 // an update on connection type change. | |
1146 EXPECT_EQ(0U, test_external_estimate_provider->update_count()); | |
1147 test_external_estimate_provider->set_time_since_last_update( | |
1148 base::TimeDelta::Max()); | |
1149 | |
1150 estimator.SimulateNetworkChangeTo( | |
1151 NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-2"); | |
1152 EXPECT_EQ( | |
1153 4U, test_external_estimate_provider->get_time_since_last_update_count()); | |
1154 EXPECT_EQ(3U, test_external_estimate_provider->get_rtt_count()); | |
1155 EXPECT_EQ( | |
1156 3U, | |
1157 test_external_estimate_provider->get_downstream_throughput_kbps_count()); | |
1158 EXPECT_EQ(1U, test_external_estimate_provider->update_count()); | |
1159 | |
1160 // Estimates are unavailable because external estimate provider never | |
1161 // notifies network quality estimator of the updated estimates. | |
1162 EXPECT_FALSE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
1163 EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
1164 } | |
1165 | |
1166 // Tests if the estimate from the external estimate provider is merged with the | |
1167 // observations collected from the HTTP requests. | |
1168 TEST(NetworkQualityEstimatorTest, TestExternalEstimateProviderMergeEstimates) { | |
1169 const base::TimeDelta external_estimate_provider_rtt = | |
1170 base::TimeDelta::FromMilliseconds(10 * 1000); | |
1171 const int32_t external_estimate_provider_downstream_throughput = 100 * 1000; | |
1172 TestExternalEstimateProvider* test_external_estimate_provider = | |
1173 new TestExternalEstimateProvider( | |
1174 external_estimate_provider_rtt, | |
1175 external_estimate_provider_downstream_throughput); | |
1176 std::unique_ptr<ExternalEstimateProvider> external_estimate_provider( | |
1177 test_external_estimate_provider); | |
1178 | |
1179 std::map<std::string, std::string> variation_params; | |
1180 TestNetworkQualityEstimator estimator(variation_params, | |
1181 std::move(external_estimate_provider)); | |
1182 | |
1183 base::TimeDelta rtt; | |
1184 // Estimate provided by network quality estimator should match the estimate | |
1185 // provided by external estimate provider. | |
1186 EXPECT_TRUE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
1187 EXPECT_EQ(external_estimate_provider_rtt, rtt); | |
1188 | |
1189 int32_t kbps; | |
1190 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
1191 EXPECT_EQ(external_estimate_provider_downstream_throughput, kbps); | |
1192 | |
1193 TestDelegate test_delegate; | |
1194 TestURLRequestContext context(true); | |
1195 context.set_network_quality_estimator(&estimator); | |
1196 context.Init(); | |
1197 | |
1198 std::unique_ptr<URLRequest> request(context.CreateRequest( | |
1199 estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate)); | |
1200 request->Start(); | |
1201 base::RunLoop().Run(); | |
1202 | |
1203 EXPECT_TRUE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
1204 EXPECT_NE(external_estimate_provider_rtt, rtt); | |
1205 | |
1206 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); | |
1207 EXPECT_NE(external_estimate_provider_downstream_throughput, kbps); | |
1208 } | |
1209 | |
1210 TEST(NetworkQualityEstimatorTest, TestObservers) { | |
1211 TestRTTObserver rtt_observer; | |
1212 TestThroughputObserver throughput_observer; | |
1213 std::map<std::string, std::string> variation_params; | |
1214 TestNetworkQualityEstimator estimator(variation_params); | |
1215 estimator.AddRTTObserver(&rtt_observer); | |
1216 estimator.AddThroughputObserver(&throughput_observer); | |
1217 | |
1218 TestDelegate test_delegate; | |
1219 TestURLRequestContext context(true); | |
1220 context.set_network_quality_estimator(&estimator); | |
1221 context.Init(); | |
1222 | |
1223 EXPECT_EQ(0U, rtt_observer.observations().size()); | |
1224 EXPECT_EQ(0U, throughput_observer.observations().size()); | |
1225 base::TimeTicks then = base::TimeTicks::Now(); | |
1226 | |
1227 std::unique_ptr<URLRequest> request(context.CreateRequest( | |
1228 estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate)); | |
1229 request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME); | |
1230 request->Start(); | |
1231 base::RunLoop().Run(); | |
1232 | |
1233 std::unique_ptr<URLRequest> request2(context.CreateRequest( | |
1234 estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate)); | |
1235 request2->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME); | |
1236 request2->Start(); | |
1237 base::RunLoop().Run(); | |
1238 | |
1239 // Both RTT and downstream throughput should be updated. | |
1240 base::TimeDelta rtt; | |
1241 EXPECT_TRUE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
1242 | |
1243 int32_t throughput; | |
1244 EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&throughput)); | |
1245 | |
1246 EXPECT_EQ(2U, rtt_observer.observations().size()); | |
1247 EXPECT_EQ(2U, throughput_observer.observations().size()); | |
1248 for (const auto& observation : rtt_observer.observations()) { | |
1249 EXPECT_LE(0, observation.rtt_ms); | |
1250 EXPECT_LE(0, (observation.timestamp - then).InMilliseconds()); | |
1251 EXPECT_EQ(NetworkQualityEstimator::URL_REQUEST, observation.source); | |
1252 } | |
1253 for (const auto& observation : throughput_observer.observations()) { | |
1254 EXPECT_LE(0, observation.throughput_kbps); | |
1255 EXPECT_LE(0, (observation.timestamp - then).InMilliseconds()); | |
1256 EXPECT_EQ(NetworkQualityEstimator::URL_REQUEST, observation.source); | |
1257 } | |
1258 | |
1259 // Verify that observations from TCP and QUIC are passed on to the observers. | |
1260 base::TimeDelta tcp_rtt(base::TimeDelta::FromMilliseconds(1)); | |
1261 base::TimeDelta quic_rtt(base::TimeDelta::FromMilliseconds(2)); | |
1262 | |
1263 std::unique_ptr<SocketPerformanceWatcher> tcp_watcher = | |
1264 estimator.GetSocketPerformanceWatcherFactory() | |
1265 ->CreateSocketPerformanceWatcher( | |
1266 SocketPerformanceWatcherFactory::PROTOCOL_TCP); | |
1267 | |
1268 std::unique_ptr<SocketPerformanceWatcher> quic_watcher = | |
1269 estimator.GetSocketPerformanceWatcherFactory() | |
1270 ->CreateSocketPerformanceWatcher( | |
1271 SocketPerformanceWatcherFactory::PROTOCOL_QUIC); | |
1272 | |
1273 tcp_watcher->OnUpdatedRTTAvailable(tcp_rtt); | |
1274 quic_watcher->OnUpdatedRTTAvailable(quic_rtt); | |
1275 | |
1276 base::RunLoop().RunUntilIdle(); | |
1277 | |
1278 EXPECT_EQ(4U, rtt_observer.observations().size()); | |
1279 EXPECT_EQ(2U, throughput_observer.observations().size()); | |
1280 | |
1281 EXPECT_EQ(tcp_rtt.InMilliseconds(), rtt_observer.observations().at(2).rtt_ms); | |
1282 EXPECT_EQ(quic_rtt.InMilliseconds(), | |
1283 rtt_observer.observations().at(3).rtt_ms); | |
1284 } | |
1285 | |
1286 // TestTCPSocketRTT requires kernel support for tcp_info struct, and so it is | |
1287 // enabled only on certain platforms. | |
1288 #if defined(TCP_INFO) || defined(OS_LINUX) | |
1289 #define MAYBE_TestTCPSocketRTT TestTCPSocketRTT | |
1290 #else | |
1291 #define MAYBE_TestTCPSocketRTT DISABLED_TestTCPSocketRTT | |
1292 #endif | |
1293 // Tests that the TCP socket notifies the Network Quality Estimator of TCP RTTs, | |
1294 // which in turn notifies registered RTT observers. | |
1295 TEST(NetworkQualityEstimatorTest, MAYBE_TestTCPSocketRTT) { | |
1296 TestRTTObserver rtt_observer; | |
1297 std::map<std::string, std::string> variation_params; | |
1298 TestNetworkQualityEstimator estimator(variation_params); | |
1299 estimator.AddRTTObserver(&rtt_observer); | |
1300 | |
1301 TestDelegate test_delegate; | |
1302 TestURLRequestContext context(true); | |
1303 context.set_network_quality_estimator(&estimator); | |
1304 | |
1305 std::unique_ptr<HttpNetworkSession::Params> params( | |
1306 new HttpNetworkSession::Params); | |
1307 // |estimator| should be notified of TCP RTT observations. | |
1308 params->socket_performance_watcher_factory = | |
1309 estimator.GetSocketPerformanceWatcherFactory(); | |
1310 context.set_http_network_session_params(std::move(params)); | |
1311 context.Init(); | |
1312 | |
1313 EXPECT_EQ(0U, rtt_observer.observations().size()); | |
1314 base::TimeDelta rtt; | |
1315 EXPECT_FALSE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
1316 | |
1317 // Send two requests. Verify that the completion of each request generates at | |
1318 // least one TCP RTT observation. | |
1319 for (size_t i = 0; i < 2; ++i) { | |
1320 size_t before_count_tcp_rtt_observations = 0; | |
1321 for (const auto& observation : rtt_observer.observations()) { | |
1322 if (observation.source == NetworkQualityEstimator::TCP) | |
1323 ++before_count_tcp_rtt_observations; | |
1324 } | |
1325 | |
1326 std::unique_ptr<URLRequest> request(context.CreateRequest( | |
1327 estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate)); | |
1328 request->Start(); | |
1329 base::RunLoop().Run(); | |
1330 | |
1331 size_t after_count_tcp_rtt_observations = 0; | |
1332 for (const auto& observation : rtt_observer.observations()) { | |
1333 if (observation.source == NetworkQualityEstimator::TCP) | |
1334 ++after_count_tcp_rtt_observations; | |
1335 } | |
1336 // At least one notification should be received per socket performance | |
1337 // watcher. | |
1338 EXPECT_LE(1U, after_count_tcp_rtt_observations - | |
1339 before_count_tcp_rtt_observations) | |
1340 << i; | |
1341 } | |
1342 EXPECT_TRUE(estimator.GetURLRequestRTTEstimate(&rtt)); | |
1343 } | |
1344 | |
1345 } // namespace net | |
OLD | NEW |