| // Copyright 2014 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <cmath> // For std::modf. |
| #include <map> |
| #include <string> |
| |
| #include "base/command_line.h" |
| #include "base/run_loop.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "build/build_config.h" |
| #include "content/browser/network/network_quality_observer_impl.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/common/content_switches.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/content_browser_test.h" |
| #include "content/public/test/content_browser_test_utils.h" |
| #include "content/shell/browser/shell.h" |
| #include "net/base/network_change_notifier.h" |
| #include "net/base/network_change_notifier_factory.h" |
| #include "net/dns/mock_host_resolver.h" |
| #include "net/log/test_net_log.h" |
| #include "net/nqe/effective_connection_type.h" |
| #include "services/network/test/test_network_quality_tracker.h" |
| |
| namespace { |
| |
| // Returns the total count of samples in |histogram|. |
| int GetTotalSampleCount(base::HistogramTester* tester, |
| const std::string& histogram) { |
| int count = 0; |
| std::vector<base::Bucket> buckets = tester->GetAllSamples(histogram); |
| for (const auto& bucket : buckets) |
| count += bucket.count; |
| return count; |
| } |
| |
| void VerifyRtt(base::TimeDelta expected_rtt, int32_t got_rtt_milliseconds) { |
| EXPECT_EQ(0, got_rtt_milliseconds % 50) |
| << " got_rtt_milliseconds=" << got_rtt_milliseconds; |
| |
| if (expected_rtt > base::Milliseconds(3000)) |
| expected_rtt = base::Milliseconds(3000); |
| |
| // The difference between the actual and the estimate value should be within |
| // 10%. Add 50 (bucket size used in Blink) to account for the cases when the |
| // sample may spill over to the next bucket due to the added noise of 10%. |
| // For example, if sample is 300 msec, after adding noise, it may become 330, |
| // and after rounding off, it would spill over to the next bucket of 350 msec. |
| EXPECT_GE((expected_rtt.InMilliseconds() * 0.1) + 50, |
| std::abs(expected_rtt.InMilliseconds() - got_rtt_milliseconds)) |
| << " expected_rtt=" << expected_rtt |
| << " got_rtt_milliseconds=" << got_rtt_milliseconds; |
| } |
| |
| void VerifyDownlinkKbps(double expected_kbps, double got_kbps) { |
| // First verify that |got_kbps| is a multiple of 50. |
| int quotient = static_cast<int>(got_kbps / 50); |
| // |mod| is the remainder left after dividing |got_kbps| by 50 while |
| // restricting the quotient to integer. For example, if |got_kbps| is |
| // 1050, then mod will be 0. If |got_kbps| is 1030, mod will be 30. |
| double mod = got_kbps - 50 * quotient; |
| EXPECT_LE(0.0, mod); |
| EXPECT_GT(50.0, mod); |
| // It is possible that |mod| is not exactly 0 because of floating point |
| // computations. e.g., |got_kbps| may be 99.999999, in which case |mod| |
| // will be 49.999999. |
| EXPECT_TRUE(mod < (1e-5) || (50 - mod) < 1e-5) << " got_kbps=" << got_kbps; |
| |
| if (expected_kbps > 10000) |
| expected_kbps = 10000; |
| |
| // The difference between the actual and the estimate value should be within |
| // 10%. Add 50 (bucket size used in Blink) to account for the cases when the |
| // sample may spill over to the next bucket due to the added noise of 10%. |
| // For example, if sample is 300 kbps, after adding noise, it may become 330, |
| // and after rounding off, it would spill over to the next bucket of 350 kbps. |
| EXPECT_GE((expected_kbps * 0.1) + 50, std::abs(expected_kbps - got_kbps)) |
| << " expected_kbps=" << expected_kbps << " got_kbps=" << got_kbps; |
| } |
| |
| class MockNetworkChangeNotifierWifi : public net::NetworkChangeNotifier { |
| public: |
| void GetCurrentMaxBandwidthAndConnectionType( |
| double* max_bandwidth_mbps, |
| ConnectionType* connection_type) const override { |
| *connection_type = NetworkChangeNotifier::CONNECTION_WIFI; |
| *max_bandwidth_mbps = |
| net::NetworkChangeNotifier::GetMaxBandwidthMbpsForConnectionSubtype( |
| net::NetworkChangeNotifier::SUBTYPE_WIFI_N); |
| } |
| ConnectionType GetCurrentConnectionType() const override { |
| return NetworkChangeNotifier::CONNECTION_WIFI; |
| } |
| }; |
| |
| } // namespace |
| |
| namespace content { |
| |
| class NetInfoBrowserTest : public content::ContentBrowserTest { |
| public: |
| NetInfoBrowserTest() |
| : test_network_quality_tracker_( |
| std::make_unique<network::TestNetworkQualityTracker>()) {} |
| |
| network::NetworkQualityTracker* GetNetworkQualityTracker() const { |
| return test_network_quality_tracker_.get(); |
| } |
| |
| protected: |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| // TODO(jkarlin): Once NetInfo is enabled on all platforms remove this |
| // switch. |
| command_line->AppendSwitch(switches::kEnableNetworkInformationDownlinkMax); |
| |
| // TODO(jkarlin): Remove this once downlinkMax is no longer |
| // experimental. |
| command_line->AppendSwitch( |
| switches::kEnableExperimentalWebPlatformFeatures); |
| } |
| |
| void SetUp() override { |
| net::NetworkChangeNotifier::SetTestNotificationsOnly(true); |
| |
| content::ContentBrowserTest::SetUp(); |
| } |
| |
| void SetUpOnMainThread() override { |
| host_resolver()->AddRule("*", "127.0.0.1"); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| static void SetConnectionType( |
| net::NetworkChangeNotifier::ConnectionType type, |
| net::NetworkChangeNotifier::ConnectionSubtype subtype) { |
| net::NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChangeForTests( |
| net::NetworkChangeNotifier::GetMaxBandwidthMbpsForConnectionSubtype( |
| subtype), |
| type); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| std::string RunScriptExtractString(const std::string& script) { |
| return EvalJs(shell(), script).ExtractString(); |
| } |
| |
| bool RunScriptExtractBool(const std::string& script) { |
| return EvalJs(shell(), script).ExtractBool(); |
| } |
| |
| double RunScriptExtractDouble(const std::string& script) { |
| return EvalJs(shell(), script).ExtractDouble(); |
| } |
| |
| int RunScriptExtractInt(const std::string& script) { |
| return EvalJs(shell(), script).ExtractInt(); |
| } |
| |
| private: |
| std::unique_ptr<network::TestNetworkQualityTracker> |
| test_network_quality_tracker_; |
| }; |
| |
| // Make sure the type is correct when the page is first opened. |
| IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, VerifyNetworkStateInitialized) { |
| // Mock out the NCN. |
| net::NetworkChangeNotifier::DisableForTest disable_for_test; |
| MockNetworkChangeNotifierWifi mock_notifier; |
| |
| EXPECT_TRUE(NavigateToURL(shell(), content::GetTestUrl("", "net_info.html"))); |
| EXPECT_TRUE(RunScriptExtractBool("getOnLine()")); |
| EXPECT_EQ("wifi", RunScriptExtractString("getType()")); |
| EXPECT_EQ(net::NetworkChangeNotifier::GetMaxBandwidthMbpsForConnectionSubtype( |
| net::NetworkChangeNotifier::SUBTYPE_WIFI_N), |
| RunScriptExtractDouble("getDownlinkMax()")); |
| } |
| |
| // Make sure that type changes in the browser make their way to |
| // navigator.connection.type. |
| IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, NetworkChangePlumbsToNavigator) { |
| EXPECT_TRUE(NavigateToURL(shell(), content::GetTestUrl("", "net_info.html"))); |
| SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI, |
| net::NetworkChangeNotifier::SUBTYPE_WIFI_N); |
| EXPECT_EQ("wifi", RunScriptExtractString("getType()")); |
| EXPECT_EQ(net::NetworkChangeNotifier::GetMaxBandwidthMbpsForConnectionSubtype( |
| net::NetworkChangeNotifier::SUBTYPE_WIFI_N), |
| RunScriptExtractDouble("getDownlinkMax()")); |
| |
| SetConnectionType(net::NetworkChangeNotifier::CONNECTION_ETHERNET, |
| net::NetworkChangeNotifier::SUBTYPE_GIGABIT_ETHERNET); |
| EXPECT_EQ("ethernet", RunScriptExtractString("getType()")); |
| EXPECT_EQ(net::NetworkChangeNotifier::GetMaxBandwidthMbpsForConnectionSubtype( |
| net::NetworkChangeNotifier::SUBTYPE_GIGABIT_ETHERNET), |
| RunScriptExtractDouble("getDownlinkMax()")); |
| } |
| |
| // Make sure that type changes in the browser make their way to |
| // navigator.isOnline. |
| IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, IsOnline) { |
| EXPECT_TRUE(NavigateToURL(shell(), content::GetTestUrl("", "net_info.html"))); |
| SetConnectionType(net::NetworkChangeNotifier::CONNECTION_ETHERNET, |
| net::NetworkChangeNotifier::SUBTYPE_GIGABIT_ETHERNET); |
| EXPECT_TRUE(RunScriptExtractBool("getOnLine()")); |
| SetConnectionType(net::NetworkChangeNotifier::CONNECTION_NONE, |
| net::NetworkChangeNotifier::SUBTYPE_NONE); |
| EXPECT_FALSE(RunScriptExtractBool("getOnLine()")); |
| SetConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI, |
| net::NetworkChangeNotifier::SUBTYPE_WIFI_N); |
| EXPECT_TRUE(RunScriptExtractBool("getOnLine()")); |
| } |
| |
| // Creating a new render view shouldn't reinitialize Blink's |
| // NetworkStateNotifier. See https://crbug.com/535081. |
| IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, TwoRenderViewsInOneProcess) { |
| SetConnectionType(net::NetworkChangeNotifier::CONNECTION_ETHERNET, |
| net::NetworkChangeNotifier::SUBTYPE_GIGABIT_ETHERNET); |
| EXPECT_TRUE(NavigateToURL(shell(), content::GetTestUrl("", "net_info.html"))); |
| EXPECT_TRUE(RunScriptExtractBool("getOnLine()")); |
| |
| SetConnectionType(net::NetworkChangeNotifier::CONNECTION_NONE, |
| net::NetworkChangeNotifier::SUBTYPE_NONE); |
| EXPECT_FALSE(RunScriptExtractBool("getOnLine()")); |
| |
| // Open the same page in a new window on the same process. |
| EXPECT_TRUE(ExecJs(shell(), "window.open(\"net_info.html\")")); |
| |
| // The network state should not have reinitialized to what it was when opening |
| // the first window (online). |
| EXPECT_FALSE(RunScriptExtractBool("getOnLine()")); |
| } |
| |
| // Verify that when the network quality notifications are not sent, the |
| // Javascript API returns a valid estimate that is multiple of 50 msec and 50 |
| // kbps. |
| IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, |
| NetworkQualityEstimatorNotInitialized) { |
| base::HistogramTester histogram_tester; |
| NetworkQualityObserverImpl impl(GetNetworkQualityTracker()); |
| |
| EXPECT_TRUE(embedded_test_server()->Start()); |
| EXPECT_TRUE( |
| NavigateToURL(shell(), embedded_test_server()->GetURL("/net_info.html"))); |
| |
| // When NQE is not initialized, the javascript calls should return default |
| // values. |
| EXPECT_EQ(0, RunScriptExtractInt("getRtt()")); |
| VerifyDownlinkKbps(10000, RunScriptExtractDouble("getDownlink()") * 1000); |
| } |
| |
| // Make sure the changes in the effective connection type are notified to the |
| // render thread. |
| IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, |
| EffectiveConnectionTypeChangeNotified) { |
| base::HistogramTester histogram_tester; |
| NetworkQualityObserverImpl impl(GetNetworkQualityTracker()); |
| |
| base::TimeDelta http_rtt(base::Milliseconds(1000)); |
| int32_t downstream_throughput_kbps = 300; |
| GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting( |
| http_rtt, downstream_throughput_kbps); |
| |
| EXPECT_TRUE(embedded_test_server()->Start()); |
| EXPECT_TRUE( |
| NavigateToURL(shell(), embedded_test_server()->GetURL("/net_info.html"))); |
| |
| FetchHistogramsFromChildProcesses(); |
| |
| int samples = |
| GetTotalSampleCount(&histogram_tester, "NQE.RenderThreadNotified"); |
| EXPECT_LT(0, samples); |
| |
| // Change effective connection type so that the renderer process is notified. |
| // Changing the effective connection type from 2G to 3G is guaranteed to |
| // generate the notification to the renderers, irrespective of the current |
| // effective connection type. |
| GetNetworkQualityTracker()->ReportEffectiveConnectionTypeForTesting( |
| net::EFFECTIVE_CONNECTION_TYPE_2G); |
| EXPECT_EQ("2g", RunScriptExtractString("getEffectiveType()")); |
| |
| GetNetworkQualityTracker()->ReportEffectiveConnectionTypeForTesting( |
| net::EFFECTIVE_CONNECTION_TYPE_3G); |
| EXPECT_EQ("3g", RunScriptExtractString("getEffectiveType()")); |
| |
| FetchHistogramsFromChildProcesses(); |
| EXPECT_GT(GetTotalSampleCount(&histogram_tester, "NQE.RenderThreadNotified"), |
| samples); |
| } |
| |
| // Make sure the changes in the network quality are notified to the render |
| // thread, and the changed network quality is accessible via Javascript API. |
| IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, NetworkQualityChangeNotified) { |
| base::HistogramTester histogram_tester; |
| NetworkQualityObserverImpl impl(GetNetworkQualityTracker()); |
| |
| base::TimeDelta http_rtt(base::Milliseconds(1000)); |
| int32_t downstream_throughput_kbps = 300; |
| |
| GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting( |
| http_rtt, downstream_throughput_kbps); |
| |
| EXPECT_TRUE(embedded_test_server()->Start()); |
| EXPECT_TRUE( |
| NavigateToURL(shell(), embedded_test_server()->GetURL("/net_info.html"))); |
| |
| FetchHistogramsFromChildProcesses(); |
| EXPECT_FALSE( |
| histogram_tester.GetAllSamples("NQE.RenderThreadNotified").empty()); |
| |
| VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()")); |
| VerifyDownlinkKbps(downstream_throughput_kbps, |
| RunScriptExtractDouble("getDownlink()") * 1000); |
| |
| // Verify that the network quality change is accessible via Javascript API. |
| http_rtt = base::Seconds(10); |
| downstream_throughput_kbps = 3000; |
| GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting( |
| http_rtt, downstream_throughput_kbps); |
| base::RunLoop().RunUntilIdle(); |
| VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()")); |
| VerifyDownlinkKbps(downstream_throughput_kbps, |
| RunScriptExtractDouble("getDownlink()") * 1000); |
| } |
| |
| // Make sure the changes in the network quality are rounded to the nearest |
| // 50 milliseconds or 50 kbps. |
| IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, NetworkQualityChangeRounded) { |
| base::HistogramTester histogram_tester; |
| NetworkQualityObserverImpl impl(GetNetworkQualityTracker()); |
| |
| // Verify that the network quality is rounded properly. |
| base::TimeDelta http_rtt(base::Milliseconds(103)); |
| int32_t downstream_throughput_kbps = 8303; |
| GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting( |
| http_rtt, downstream_throughput_kbps); |
| |
| EXPECT_TRUE(embedded_test_server()->Start()); |
| EXPECT_TRUE( |
| NavigateToURL(shell(), embedded_test_server()->GetURL("/net_info.html"))); |
| VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()")); |
| VerifyDownlinkKbps(downstream_throughput_kbps, |
| RunScriptExtractDouble("getDownlink()") * 1000); |
| |
| http_rtt = base::Milliseconds(1103); |
| downstream_throughput_kbps = 1307; |
| GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting( |
| http_rtt, downstream_throughput_kbps); |
| base::RunLoop().RunUntilIdle(); |
| VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()")); |
| VerifyDownlinkKbps(downstream_throughput_kbps, |
| RunScriptExtractDouble("getDownlink()") * 1000); |
| |
| http_rtt = base::Milliseconds(2112); |
| downstream_throughput_kbps = 2112; |
| GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting( |
| http_rtt, downstream_throughput_kbps); |
| base::RunLoop().RunUntilIdle(); |
| VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()")); |
| VerifyDownlinkKbps(downstream_throughput_kbps, |
| RunScriptExtractDouble("getDownlink()") * 1000); |
| } |
| |
| // Make sure the network quality are rounded down when it exceeds the upper |
| // limit. |
| IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, NetworkQualityChangeUpperLimit) { |
| base::HistogramTester histogram_tester; |
| NetworkQualityObserverImpl impl(GetNetworkQualityTracker()); |
| |
| base::TimeDelta http_rtt(base::Milliseconds(12003)); |
| int32_t downstream_throughput_kbps = 30300; |
| |
| GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting( |
| http_rtt, downstream_throughput_kbps); |
| |
| EXPECT_TRUE(embedded_test_server()->Start()); |
| EXPECT_TRUE( |
| NavigateToURL(shell(), embedded_test_server()->GetURL("/net_info.html"))); |
| VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()")); |
| VerifyDownlinkKbps(downstream_throughput_kbps, |
| RunScriptExtractDouble("getDownlink()") * 1000); |
| } |
| |
| // Make sure the noise added to the network quality varies with the hostname. |
| IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, NetworkQualityRandomized) { |
| base::HistogramTester histogram_tester; |
| NetworkQualityObserverImpl impl(GetNetworkQualityTracker()); |
| |
| base::TimeDelta http_rtt(base::Milliseconds(2000)); |
| int32_t downstream_throughput_kbps = 3000; |
| |
| GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting( |
| http_rtt, downstream_throughput_kbps); |
| |
| EXPECT_TRUE(embedded_test_server()->Start()); |
| |
| EXPECT_TRUE( |
| NavigateToURL(shell(), embedded_test_server()->GetURL("/net_info.html"))); |
| VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()")); |
| VerifyDownlinkKbps(downstream_throughput_kbps, |
| RunScriptExtractDouble("getDownlink()") * 1000); |
| |
| const int32_t rtt_noise_milliseconds = RunScriptExtractInt("getRtt()") - 2000; |
| const int32_t downlink_noise_kbps = |
| RunScriptExtractDouble("getDownlink()") * 1000 - 3000; |
| |
| // When the hostname is not changed, the noise should not change. |
| EXPECT_TRUE( |
| NavigateToURL(shell(), embedded_test_server()->GetURL("/net_info.html"))); |
| VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()")); |
| VerifyDownlinkKbps(downstream_throughput_kbps, |
| RunScriptExtractDouble("getDownlink()") * 1000); |
| EXPECT_EQ(rtt_noise_milliseconds, RunScriptExtractInt("getRtt()") - 2000); |
| EXPECT_EQ(downlink_noise_kbps, |
| RunScriptExtractDouble("getDownlink()") * 1000 - 3000); |
| |
| // Verify that changing the hostname changes the noise. It is possible that |
| // the hash of a different host also maps to the same bucket among 20 buckets. |
| // Try 10 different hosts. This reduces the probability of failure of this |
| // test to (1/20)^10 = 9,7 * 10^-14. |
| for (size_t i = 0; i < 10; ++i) { |
| // The noise added is a function of the hostname. Varying the hostname |
| // should vary the noise. |
| std::string fake_hostname = "example" + base::NumberToString(i) + ".com"; |
| EXPECT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL( |
| fake_hostname, "/net_info.html"))); |
| VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()")); |
| VerifyDownlinkKbps(downstream_throughput_kbps, |
| RunScriptExtractDouble("getDownlink()") * 1000); |
| |
| int32_t new_rtt_noise_milliseconds = RunScriptExtractInt("getRtt()") - 2000; |
| int32_t new_downlink_noise_kbps = |
| RunScriptExtractDouble("getDownlink()") * 1000 - 3000; |
| |
| if (rtt_noise_milliseconds != new_rtt_noise_milliseconds && |
| downlink_noise_kbps != new_downlink_noise_kbps) { |
| return; |
| } |
| } |
| NOTREACHED() << "Noise not added to the network quality estimates"; |
| } |
| |
| // Make sure the minor changes (<10%) in the network quality are not notified. |
| IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, NetworkQualityChangeNotNotified) { |
| base::HistogramTester histogram_tester; |
| NetworkQualityObserverImpl impl(GetNetworkQualityTracker()); |
| |
| // Verify that the network quality is rounded properly. |
| base::TimeDelta http_rtt(base::Milliseconds(1123)); |
| int32_t downstream_throughput_kbps = 1303; |
| GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting( |
| http_rtt, downstream_throughput_kbps); |
| |
| EXPECT_TRUE(embedded_test_server()->Start()); |
| EXPECT_TRUE( |
| NavigateToURL(shell(), embedded_test_server()->GetURL("/net_info.html"))); |
| VerifyRtt(http_rtt, RunScriptExtractInt("getRtt()")); |
| VerifyDownlinkKbps(downstream_throughput_kbps, |
| RunScriptExtractDouble("getDownlink()") * 1000); |
| |
| // All the 3 metrics change by less than 10%. So, the observers are not |
| // notified. |
| http_rtt = base::Milliseconds(1223); |
| downstream_throughput_kbps = 1403; |
| GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting( |
| http_rtt, downstream_throughput_kbps); |
| base::RunLoop().RunUntilIdle(); |
| VerifyRtt(base::Milliseconds(1100), RunScriptExtractInt("getRtt()")); |
| VerifyDownlinkKbps(1300, RunScriptExtractDouble("getDownlink()") * 1000); |
| |
| // HTTP RTT has changed by more than 10% from the last notified value of |
| // |network_quality_1|. The observers should be notified. |
| http_rtt = base::Milliseconds(2223); |
| downstream_throughput_kbps = 1403; |
| GetNetworkQualityTracker()->ReportRTTsAndThroughputForTesting( |
| http_rtt, downstream_throughput_kbps); |
| base::RunLoop().RunUntilIdle(); |
| VerifyRtt(base::Milliseconds(2200), RunScriptExtractInt("getRtt()")); |
| VerifyDownlinkKbps(1400, RunScriptExtractDouble("getDownlink()") * 1000); |
| } |
| |
| } // namespace content |