1 // Copyright 2014 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 <cmath>  // For std::modf.
6 #include <map>
7 #include <string>
8 
9 #include "base/command_line.h"
10 #include "base/run_loop.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/test/metrics/histogram_tester.h"
13 #include "build/build_config.h"
14 #include "content/browser/net/network_quality_observer_impl.h"
15 #include "content/public/browser/render_process_host.h"
16 #include "content/public/common/content_switches.h"
17 #include "content/public/test/browser_test.h"
18 #include "content/public/test/browser_test_utils.h"
19 #include "content/public/test/content_browser_test.h"
20 #include "content/public/test/content_browser_test_utils.h"
21 #include "content/shell/browser/shell.h"
22 #include "net/base/network_change_notifier.h"
23 #include "net/base/network_change_notifier_factory.h"
24 #include "net/dns/mock_host_resolver.h"
25 #include "net/log/test_net_log.h"
26 #include "net/nqe/effective_connection_type.h"
27 #include "services/network/test/test_network_quality_tracker.h"
28 
29 namespace {
30 
31 // Returns the total count of samples in |histogram|.
GetTotalSampleCount(base::HistogramTester * tester,const std::string & histogram)32 int GetTotalSampleCount(base::HistogramTester* tester,
33                         const std::string& histogram) {
34   int count = 0;
35   std::vector<base::Bucket> buckets = tester->GetAllSamples(histogram);
36   for (const auto& bucket : buckets)
37     count += bucket.count;
38   return count;
39 }
40 
VerifyRtt(base::TimeDelta expected_rtt,int32_t got_rtt_milliseconds)41 void VerifyRtt(base::TimeDelta expected_rtt, int32_t got_rtt_milliseconds) {
42   EXPECT_EQ(0, got_rtt_milliseconds % 50)
43       << " got_rtt_milliseconds=" << got_rtt_milliseconds;
44 
45   if (expected_rtt > base::TimeDelta::FromMilliseconds(3000))
46     expected_rtt = base::TimeDelta::FromMilliseconds(3000);
47 
48   // The difference between the actual and the estimate value should be within
49   // 10%. Add 50 (bucket size used in Blink) to account for the cases when the
50   // sample may spill over to the next bucket due to the added noise of 10%.
51   // For example, if sample is 300 msec, after adding noise, it may become 330,
52   // and after rounding off, it would spill over to the next bucket of 350 msec.
53   EXPECT_GE((expected_rtt.InMilliseconds() * 0.1) + 50,
54             std::abs(expected_rtt.InMilliseconds() - got_rtt_milliseconds))
55       << " expected_rtt=" << expected_rtt
56       << " got_rtt_milliseconds=" << got_rtt_milliseconds;
57 }
58 
VerifyDownlinkKbps(double expected_kbps,double got_kbps)59 void VerifyDownlinkKbps(double expected_kbps, double got_kbps) {
60   // First verify that |got_kbps| is a multiple of 50.
61   int quotient = static_cast<int>(got_kbps / 50);
62   // |mod| is the remainder left after dividing |got_kbps| by 50 while
63   // restricting the quotient to integer.  For example, if |got_kbps| is
64   // 1050, then mod will be 0. If |got_kbps| is 1030, mod will be 30.
65   double mod = got_kbps - 50 * quotient;
66   EXPECT_LE(0.0, mod);
67   EXPECT_GT(50.0, mod);
68   // It is possible that |mod| is not exactly 0 because of floating point
69   // computations. e.g., |got_kbps| may be 99.999999, in which case |mod|
70   // will be 49.999999.
71   EXPECT_TRUE(mod < (1e-5) || (50 - mod) < 1e-5) << " got_kbps=" << got_kbps;
72 
73   if (expected_kbps > 10000)
74     expected_kbps = 10000;
75 
76   // The difference between the actual and the estimate value should be within
77   // 10%. Add 50 (bucket size used in Blink) to account for the cases when the
78   // sample may spill over to the next bucket due to the added noise of 10%.
79   // For example, if sample is 300 kbps, after adding noise, it may become 330,
80   // and after rounding off, it would spill over to the next bucket of 350 kbps.
81   EXPECT_GE((expected_kbps * 0.1) + 50, std::abs(expected_kbps - got_kbps))
82       << " expected_kbps=" << expected_kbps << " got_kbps=" << got_kbps;
83 }
84 
85 class MockNetworkChangeNotifierWifi : public net::NetworkChangeNotifier {
86  public:
GetCurrentMaxBandwidthAndConnectionType(double * max_bandwidth_mbps,ConnectionType * connection_type) const87   void GetCurrentMaxBandwidthAndConnectionType(
88       double* max_bandwidth_mbps,
89       ConnectionType* connection_type) const override {
90     *connection_type = NetworkChangeNotifier::CONNECTION_WIFI;
91     *max_bandwidth_mbps =
92         net::NetworkChangeNotifier::GetMaxBandwidthMbpsForConnectionSubtype(
93             net::NetworkChangeNotifier::SUBTYPE_WIFI_N);
94   }
GetCurrentConnectionType() const95   ConnectionType GetCurrentConnectionType() const override {
96     return NetworkChangeNotifier::CONNECTION_WIFI;
97   }
98 };
99 
100 }  // namespace
101 
102 namespace content {
103 
104 class NetInfoBrowserTest : public content::ContentBrowserTest {
105  public:
NetInfoBrowserTest()106   NetInfoBrowserTest()
107       : test_network_quality_tracker_(
108             std::make_unique<network::TestNetworkQualityTracker>()) {}
109 
GetNetworkQualityTracker() const110   network::NetworkQualityTracker* GetNetworkQualityTracker() const {
111     return test_network_quality_tracker_.get();
112   }
113 
114  protected:
SetUpCommandLine(base::CommandLine * command_line)115   void SetUpCommandLine(base::CommandLine* command_line) override {
116     // TODO(jkarlin): Once NetInfo is enabled on all platforms remove this
117     // switch.
118     command_line->AppendSwitch(switches::kEnableNetworkInformationDownlinkMax);
119 
120     // TODO(jkarlin): Remove this once downlinkMax is no longer
121     // experimental.
122     command_line->AppendSwitch(
123         switches::kEnableExperimentalWebPlatformFeatures);
124   }
125 
SetUp()126   void SetUp() override {
127     net::NetworkChangeNotifier::SetTestNotificationsOnly(true);
128 
129     content::ContentBrowserTest::SetUp();
130   }
131 
SetUpOnMainThread()132   void SetUpOnMainThread() override {
133     host_resolver()->AddRule("*", "127.0.0.1");
134     base::RunLoop().RunUntilIdle();
135   }
136 
SetConnectionType(net::NetworkChangeNotifier::ConnectionType type,net::NetworkChangeNotifier::ConnectionSubtype subtype)137   static void SetConnectionType(
138       net::NetworkChangeNotifier::ConnectionType type,
139       net::NetworkChangeNotifier::ConnectionSubtype subtype) {
140     net::NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChangeForTests(
141         net::NetworkChangeNotifier::GetMaxBandwidthMbpsForConnectionSubtype(
142             subtype),
143         type);
144     base::RunLoop().RunUntilIdle();
145   }
146 
RunScriptExtractString(const std::string & script)147   std::string RunScriptExtractString(const std::string& script) {
148     std::string data;
149     EXPECT_TRUE(ExecuteScriptAndExtractString(shell(), script, &data));
150     return data;
151   }
152 
RunScriptExtractBool(const std::string & script)153   bool RunScriptExtractBool(const std::string& script) {
154     bool data;
155     EXPECT_TRUE(ExecuteScriptAndExtractBool(shell(), script, &data));
156     return data;
157   }
158 
RunScriptExtractDouble(const std::string & script)159   double RunScriptExtractDouble(const std::string& script) {
160     double data = 0.0;
161     EXPECT_TRUE(ExecuteScriptAndExtractDouble(shell(), script, &data));
162     return data;
163   }
164 
RunScriptExtractInt(const std::string & script)165   int RunScriptExtractInt(const std::string& script) {
166     int data = 0;
167     EXPECT_TRUE(ExecuteScriptAndExtractInt(shell(), script, &data));
168     return data;
169   }
170 
171  private:
172   std::unique_ptr<network::TestNetworkQualityTracker>
173       test_network_quality_tracker_;
174 };
175 
176 // Make sure the type is correct when the page is first opened.
IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest,VerifyNetworkStateInitialized)177 IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, VerifyNetworkStateInitialized) {
178   // Mock out the NCN.
179   net::NetworkChangeNotifier::DisableForTest disable_for_test;
180   MockNetworkChangeNotifierWifi mock_notifier;
181 
182   EXPECT_TRUE(NavigateToURL(shell(), content::GetTestUrl("", "net_info.html")));
183   EXPECT_TRUE(RunScriptExtractBool("getOnLine()"));
184   EXPECT_EQ("wifi", RunScriptExtractString("getType()"));
185   EXPECT_EQ(net::NetworkChangeNotifier::GetMaxBandwidthMbpsForConnectionSubtype(
186                 net::NetworkChangeNotifier::SUBTYPE_WIFI_N),
187             RunScriptExtractDouble("getDownlinkMax()"));
188 }
189 
190 // Make sure that type changes in the browser make their way to
191 // navigator.connection.type.
IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest,NetworkChangePlumbsToNavigator)192 IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, NetworkChangePlumbsToNavigator) {
193   EXPECT_TRUE(NavigateToURL(shell(), content::GetTestUrl("", "net_info.html")));
194   SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI,
195                     net::NetworkChangeNotifier::SUBTYPE_WIFI_N);
196   EXPECT_EQ("wifi", RunScriptExtractString("getType()"));
197   EXPECT_EQ(net::NetworkChangeNotifier::GetMaxBandwidthMbpsForConnectionSubtype(
198                 net::NetworkChangeNotifier::SUBTYPE_WIFI_N),
199             RunScriptExtractDouble("getDownlinkMax()"));
200 
201   SetConnectionType(net::NetworkChangeNotifier::CONNECTION_ETHERNET,
202                     net::NetworkChangeNotifier::SUBTYPE_GIGABIT_ETHERNET);
203   EXPECT_EQ("ethernet", RunScriptExtractString("getType()"));
204   EXPECT_EQ(net::NetworkChangeNotifier::GetMaxBandwidthMbpsForConnectionSubtype(
205                 net::NetworkChangeNotifier::SUBTYPE_GIGABIT_ETHERNET),
206             RunScriptExtractDouble("getDownlinkMax()"));
207 }
208 
209 // Make sure that type changes in the browser make their way to
210 // navigator.isOnline.
IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest,IsOnline)211 IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, IsOnline) {
212   EXPECT_TRUE(NavigateToURL(shell(), content::GetTestUrl("", "net_info.html")));
213   SetConnectionType(net::NetworkChangeNotifier::CONNECTION_ETHERNET,
214                     net::NetworkChangeNotifier::SUBTYPE_GIGABIT_ETHERNET);
215   EXPECT_TRUE(RunScriptExtractBool("getOnLine()"));
216   SetConnectionType(net::NetworkChangeNotifier::CONNECTION_NONE,
217                     net::NetworkChangeNotifier::SUBTYPE_NONE);
218   EXPECT_FALSE(RunScriptExtractBool("getOnLine()"));
219   SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI,
220                     net::NetworkChangeNotifier::SUBTYPE_WIFI_N);
221   EXPECT_TRUE(RunScriptExtractBool("getOnLine()"));
222 }
223 
224 // Creating a new render view shouldn't reinitialize Blink's
225 // NetworkStateNotifier. See https://crbug.com/535081.
IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest,TwoRenderViewsInOneProcess)226 IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, TwoRenderViewsInOneProcess) {
227   SetConnectionType(net::NetworkChangeNotifier::CONNECTION_ETHERNET,
228                     net::NetworkChangeNotifier::SUBTYPE_GIGABIT_ETHERNET);
229   EXPECT_TRUE(NavigateToURL(shell(), content::GetTestUrl("", "net_info.html")));
230   EXPECT_TRUE(RunScriptExtractBool("getOnLine()"));
231 
232   SetConnectionType(net::NetworkChangeNotifier::CONNECTION_NONE,
233                     net::NetworkChangeNotifier::SUBTYPE_NONE);
234   EXPECT_FALSE(RunScriptExtractBool("getOnLine()"));
235 
236   // Open the same page in a new window on the same process.
237   EXPECT_TRUE(ExecuteScript(shell(), "window.open(\"net_info.html\")"));
238 
239   // The network state should not have reinitialized to what it was when opening
240   // the first window (online).
241   EXPECT_FALSE(RunScriptExtractBool("getOnLine()"));
242 }
243 
244 // Verify that when the network quality notifications are not sent, the
245 // Javascript API returns a valid estimate that is multiple of 50 msec and 50
246 // kbps.
IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest,NetworkQualityEstimatorNotInitialized)247 IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest,
248                        NetworkQualityEstimatorNotInitialized) {
249   base::HistogramTester histogram_tester;
250   NetworkQualityObserverImpl impl(GetNetworkQualityTracker());
251 
252   EXPECT_TRUE(embedded_test_server()->Start());
253   EXPECT_TRUE(
254       NavigateToURL(shell(), embedded_test_server()->GetURL("/net_info.html")));
255 
256   // When NQE is not initialized, the javascript calls should return default
257   // values.
258   EXPECT_EQ(0, RunScriptExtractInt("getRtt()"));
259   VerifyDownlinkKbps(10000, RunScriptExtractDouble("getDownlink()") * 1000);
260 }
261 
262 // Make sure the changes in the effective connection type are notified to the
263 // render thread.
IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest,EffectiveConnectionTypeChangeNotified)264 IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest,
265                        EffectiveConnectionTypeChangeNotified) {
266   base::HistogramTester histogram_tester;
267   NetworkQualityObserverImpl impl(GetNetworkQualityTracker());
268 
269   base::TimeDelta http_rtt(base::TimeDelta::FromMilliseconds(1000));
270   int32_t downstream_throughput_kbps = 300;
271   GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting(
272       http_rtt, downstream_throughput_kbps);
273 
274   EXPECT_TRUE(embedded_test_server()->Start());
275   EXPECT_TRUE(
276       NavigateToURL(shell(), embedded_test_server()->GetURL("/net_info.html")));
277 
278   FetchHistogramsFromChildProcesses();
279 
280   int samples =
281       GetTotalSampleCount(&histogram_tester, "NQE.RenderThreadNotified");
282   EXPECT_LT(0, samples);
283 
284   // Change effective connection type so that the renderer process is notified.
285   // Changing the effective connection type from 2G to 3G is guaranteed to
286   // generate the notification to the renderers, irrespective of the current
287   // effective connection type.
288   GetNetworkQualityTracker()->ReportEffectiveConnectionTypeForTesting(
289       net::EFFECTIVE_CONNECTION_TYPE_2G);
290   EXPECT_EQ("2g", RunScriptExtractString("getEffectiveType()"));
291 
292   GetNetworkQualityTracker()->ReportEffectiveConnectionTypeForTesting(
293       net::EFFECTIVE_CONNECTION_TYPE_3G);
294   EXPECT_EQ("3g", RunScriptExtractString("getEffectiveType()"));
295 
296   FetchHistogramsFromChildProcesses();
297   EXPECT_GT(GetTotalSampleCount(&histogram_tester, "NQE.RenderThreadNotified"),
298             samples);
299 }
300 
301 // Make sure the changes in the network quality are notified to the render
302 // thread, and the changed network quality is accessible via Javascript API.
IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest,NetworkQualityChangeNotified)303 IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, NetworkQualityChangeNotified) {
304   base::HistogramTester histogram_tester;
305   NetworkQualityObserverImpl impl(GetNetworkQualityTracker());
306 
307   base::TimeDelta http_rtt(base::TimeDelta::FromMilliseconds(1000));
308   int32_t downstream_throughput_kbps = 300;
309 
310   GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting(
311       http_rtt, downstream_throughput_kbps);
312 
313   EXPECT_TRUE(embedded_test_server()->Start());
314   EXPECT_TRUE(
315       NavigateToURL(shell(), embedded_test_server()->GetURL("/net_info.html")));
316 
317   FetchHistogramsFromChildProcesses();
318   EXPECT_FALSE(
319       histogram_tester.GetAllSamples("NQE.RenderThreadNotified").empty());
320 
321   VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()"));
322   VerifyDownlinkKbps(downstream_throughput_kbps,
323                      RunScriptExtractDouble("getDownlink()") * 1000);
324 
325   // Verify that the network quality change is accessible via Javascript API.
326   http_rtt = base::TimeDelta::FromSeconds(10);
327   downstream_throughput_kbps = 3000;
328   GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting(
329       http_rtt, downstream_throughput_kbps);
330   base::RunLoop().RunUntilIdle();
331   VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()"));
332   VerifyDownlinkKbps(downstream_throughput_kbps,
333                      RunScriptExtractDouble("getDownlink()") * 1000);
334 }
335 
336 // Make sure the changes in the network quality are rounded to the nearest
337 // 50 milliseconds or 50 kbps.
IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest,NetworkQualityChangeRounded)338 IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, NetworkQualityChangeRounded) {
339   base::HistogramTester histogram_tester;
340   NetworkQualityObserverImpl impl(GetNetworkQualityTracker());
341 
342   // Verify that the network quality is rounded properly.
343   base::TimeDelta http_rtt(base::TimeDelta::FromMilliseconds(103));
344   int32_t downstream_throughput_kbps = 8303;
345   GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting(
346       http_rtt, downstream_throughput_kbps);
347 
348   EXPECT_TRUE(embedded_test_server()->Start());
349   EXPECT_TRUE(
350       NavigateToURL(shell(), embedded_test_server()->GetURL("/net_info.html")));
351   VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()"));
352   VerifyDownlinkKbps(downstream_throughput_kbps,
353                      RunScriptExtractDouble("getDownlink()") * 1000);
354 
355   http_rtt = base::TimeDelta::FromMilliseconds(1103);
356   downstream_throughput_kbps = 1307;
357   GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting(
358       http_rtt, downstream_throughput_kbps);
359   base::RunLoop().RunUntilIdle();
360   VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()"));
361   VerifyDownlinkKbps(downstream_throughput_kbps,
362                      RunScriptExtractDouble("getDownlink()") * 1000);
363 
364   http_rtt = base::TimeDelta::FromMilliseconds(2112);
365   downstream_throughput_kbps = 2112;
366   GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting(
367       http_rtt, downstream_throughput_kbps);
368   base::RunLoop().RunUntilIdle();
369   VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()"));
370   VerifyDownlinkKbps(downstream_throughput_kbps,
371                      RunScriptExtractDouble("getDownlink()") * 1000);
372 }
373 
374 // Make sure the network quality are rounded down when it exceeds the upper
375 // limit.
IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest,NetworkQualityChangeUpperLimit)376 IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, NetworkQualityChangeUpperLimit) {
377   base::HistogramTester histogram_tester;
378   NetworkQualityObserverImpl impl(GetNetworkQualityTracker());
379 
380   base::TimeDelta http_rtt(base::TimeDelta::FromMilliseconds(12003));
381   int32_t downstream_throughput_kbps = 30300;
382 
383   GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting(
384       http_rtt, downstream_throughput_kbps);
385 
386   EXPECT_TRUE(embedded_test_server()->Start());
387   EXPECT_TRUE(
388       NavigateToURL(shell(), embedded_test_server()->GetURL("/net_info.html")));
389   VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()"));
390   VerifyDownlinkKbps(downstream_throughput_kbps,
391                      RunScriptExtractDouble("getDownlink()") * 1000);
392 }
393 
394 // Make sure the noise added to the network quality varies with the hostname.
IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest,NetworkQualityRandomized)395 IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, NetworkQualityRandomized) {
396   base::HistogramTester histogram_tester;
397   NetworkQualityObserverImpl impl(GetNetworkQualityTracker());
398 
399   base::TimeDelta http_rtt(base::TimeDelta::FromMilliseconds(2000));
400   int32_t downstream_throughput_kbps = 3000;
401 
402   GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting(
403       http_rtt, downstream_throughput_kbps);
404 
405   EXPECT_TRUE(embedded_test_server()->Start());
406 
407   EXPECT_TRUE(
408       NavigateToURL(shell(), embedded_test_server()->GetURL("/net_info.html")));
409   VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()"));
410   VerifyDownlinkKbps(downstream_throughput_kbps,
411                      RunScriptExtractDouble("getDownlink()") * 1000);
412 
413   const int32_t rtt_noise_milliseconds = RunScriptExtractInt("getRtt()") - 2000;
414   const int32_t downlink_noise_kbps =
415       RunScriptExtractDouble("getDownlink()") * 1000 - 3000;
416 
417   // When the hostname is not changed, the noise should not change.
418   EXPECT_TRUE(
419       NavigateToURL(shell(), embedded_test_server()->GetURL("/net_info.html")));
420   VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()"));
421   VerifyDownlinkKbps(downstream_throughput_kbps,
422                      RunScriptExtractDouble("getDownlink()") * 1000);
423   EXPECT_EQ(rtt_noise_milliseconds, RunScriptExtractInt("getRtt()") - 2000);
424   EXPECT_EQ(downlink_noise_kbps,
425             RunScriptExtractDouble("getDownlink()") * 1000 - 3000);
426 
427   // Verify that changing the hostname changes the noise. It is possible that
428   // the hash of a different host also maps to the same bucket among 20 buckets.
429   // Try 10 different hosts. This reduces the probability of failure of this
430   // test to (1/20)^10 = 9,7 * 10^-14.
431   for (size_t i = 0; i < 10; ++i) {
432     // The noise added is a function of the hostname. Varying the hostname
433     // should vary the noise.
434     std::string fake_hostname = "example" + base::NumberToString(i) + ".com";
435     EXPECT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL(
436                                            fake_hostname, "/net_info.html")));
437     VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()"));
438     VerifyDownlinkKbps(downstream_throughput_kbps,
439                        RunScriptExtractDouble("getDownlink()") * 1000);
440 
441     int32_t new_rtt_noise_milliseconds = RunScriptExtractInt("getRtt()") - 2000;
442     int32_t new_downlink_noise_kbps =
443         RunScriptExtractDouble("getDownlink()") * 1000 - 3000;
444 
445     if (rtt_noise_milliseconds != new_rtt_noise_milliseconds &&
446         downlink_noise_kbps != new_downlink_noise_kbps) {
447       return;
448     }
449   }
450   NOTREACHED() << "Noise not added to the network quality estimates";
451 }
452 
453 // Make sure the minor changes (<10%) in the network quality are not notified.
IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest,NetworkQualityChangeNotNotified)454 IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, NetworkQualityChangeNotNotified) {
455   base::HistogramTester histogram_tester;
456   NetworkQualityObserverImpl impl(GetNetworkQualityTracker());
457 
458   // Verify that the network quality is rounded properly.
459   base::TimeDelta http_rtt(base::TimeDelta::FromMilliseconds(1123));
460   int32_t downstream_throughput_kbps = 1303;
461   GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting(
462       http_rtt, downstream_throughput_kbps);
463 
464   EXPECT_TRUE(embedded_test_server()->Start());
465   EXPECT_TRUE(
466       NavigateToURL(shell(), embedded_test_server()->GetURL("/net_info.html")));
467   VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()"));
468   VerifyDownlinkKbps(downstream_throughput_kbps,
469                      RunScriptExtractDouble("getDownlink()") * 1000);
470 
471   // All the 3 metrics change by less than 10%. So, the observers are not
472   // notified.
473   http_rtt = base::TimeDelta::FromMilliseconds(1223);
474   downstream_throughput_kbps = 1403;
475   GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting(
476       http_rtt, downstream_throughput_kbps);
477   base::RunLoop().RunUntilIdle();
478   VerifyRtt(base::TimeDelta::FromMilliseconds(1100),
479             RunScriptExtractInt("getRtt()"));
480   VerifyDownlinkKbps(1300, RunScriptExtractDouble("getDownlink()") * 1000);
481 
482   // HTTP RTT has changed by more than 10% from the last notified value of
483   // |network_quality_1|. The observers should be notified.
484   http_rtt = base::TimeDelta::FromMilliseconds(2223);
485   downstream_throughput_kbps = 1403;
486   GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting(
487       http_rtt, downstream_throughput_kbps);
488   base::RunLoop().RunUntilIdle();
489   VerifyRtt(base::TimeDelta::FromMilliseconds(2200),
490             RunScriptExtractInt("getRtt()"));
491   VerifyDownlinkKbps(1400, RunScriptExtractDouble("getDownlink()") * 1000);
492 }
493 
494 }  // namespace content
495