Commit f8d8a935 authored by Tarun Bansal's avatar Tarun Bansal Committed by Commit Bot

Add logic for holdback experiment for network quality estimator Web APIs.

When the holdback experiment is enabled, the NetInfo
network quality related Web APIs (https://wicg.github.io/netinfo/)
would report network quality corresponding to the experiment
params.

This CL only affects the NetInfo JavaScript APIs. A subsequent CL
will use the framework in this CL to also override the values
of network quality reported in network quality related client hints
headers.

Change-Id: Iab9d4ecfe7c14eb5d3cee26dbf209fd943156333
Bug: 880545
Reviewed-on: https://chromium-review.googlesource.com/1201343
Commit-Queue: Tarun Bansal <tbansal@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarRyan Sturm <ryansturm@chromium.org>
Reviewed-by: default avatarJosh Karlin <jkarlin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#590212}
parent 479efc9a
...@@ -3184,6 +3184,25 @@ void ChromeContentBrowserClient::OverrideWebkitPrefs( ...@@ -3184,6 +3184,25 @@ void ChromeContentBrowserClient::OverrideWebkitPrefs(
} }
} }
if (base::FeatureList::IsEnabled(
features::kNetworkQualityEstimatorWebHoldback)) {
std::string effective_connection_type_param =
base::GetFieldTrialParamValueByFeature(
features::kNetworkQualityEstimatorWebHoldback,
"web_effective_connection_type_override");
base::Optional<net::EffectiveConnectionType> effective_connection_type =
net::GetEffectiveConnectionTypeForName(effective_connection_type_param);
DCHECK(effective_connection_type_param.empty() ||
effective_connection_type);
if (effective_connection_type) {
DCHECK_NE(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
effective_connection_type.value());
web_prefs->network_quality_estimator_web_holdback =
effective_connection_type.value();
}
}
#if !defined(OS_ANDROID) #if !defined(OS_ANDROID)
if (IsAutoplayAllowedByPolicy(contents, prefs)) { if (IsAutoplayAllowedByPolicy(contents, prefs)) {
// If autoplay is allowed by policy then force the no user gesture required // If autoplay is allowed by policy then force the no user gesture required
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include "base/metrics/field_trial_param_associator.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_impl.h"
#include "chrome/browser/chrome_content_browser_client.h"
#include "chrome/browser/net/system_network_context_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/common/content_features.h"
#include "content/public/common/service_manager_connection.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_base.h"
#include "content/public/test/browser_test_utils.h"
#include "net/nqe/effective_connection_type.h"
#include "net/nqe/network_quality_estimator.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "services/network/network_service.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/network_quality_tracker.h"
namespace {
// Simulates a network quality change. This is only called when network service
// is running in the browser process, in which case, the network quality
// estimator lives on the browser IO thread.
void SimulateNetworkQualityChangeOnIO(net::EffectiveConnectionType type) {
DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
DCHECK(content::GetNetworkServiceImpl());
DCHECK(content::GetNetworkServiceImpl()->network_quality_estimator());
content::GetNetworkServiceImpl()
->network_quality_estimator()
->SimulateNetworkQualityChangeForTesting(type);
base::RunLoop().RunUntilIdle();
}
} // namespace
// Tests if the save data header holdback works as expected.
class NetInfoNetworkQualityEstimatorHoldbackBrowserTest
: public InProcessBrowserTest,
public testing::WithParamInterface<bool> {
protected:
NetInfoNetworkQualityEstimatorHoldbackBrowserTest()
: network_service_enabled_(
base::FeatureList::IsEnabled(network::features::kNetworkService)) {
ConfigureHoldbackExperiment();
}
void SetUp() override {
test_server_.ServeFilesFromSourceDirectory("content/test/data");
ASSERT_TRUE(test_server_.Start());
InProcessBrowserTest::SetUp();
}
void VerifyNetworkQualityNetInfoWebAPI(
const std::string& expected_effective_connection_type) {
ui_test_utils::NavigateToURL(browser(),
test_server_.GetURL("/net_info.html"));
EXPECT_EQ(expected_effective_connection_type,
RunScriptExtractString("getEffectiveType()"));
if (expected_effective_connection_type == "slow-2g") {
VerifyRtt(base::TimeDelta::FromMilliseconds(3600),
RunScriptExtractDouble("getRtt()"));
VerifyDownlinkKbps(40, RunScriptExtractDouble("getDownlink()") * 1000);
} else if (expected_effective_connection_type == "2g") {
VerifyRtt(base::TimeDelta::FromMilliseconds(1800),
RunScriptExtractDouble("getRtt()"));
VerifyDownlinkKbps(75, RunScriptExtractDouble("getDownlink()") * 1000);
} else if (expected_effective_connection_type == "3g") {
VerifyRtt(base::TimeDelta::FromMilliseconds(450),
RunScriptExtractDouble("getRtt()"));
VerifyDownlinkKbps(400, RunScriptExtractDouble("getDownlink()") * 1000);
} else if (expected_effective_connection_type == "4g") {
VerifyRtt(base::TimeDelta::FromMilliseconds(175),
RunScriptExtractDouble("getRtt()"));
VerifyDownlinkKbps(1600, RunScriptExtractDouble("getDownlink()") * 1000);
} else {
DCHECK(false);
}
}
void ConfigureHoldbackExperiment() {
base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
const std::string kTrialName = "TrialFoo";
const std::string kGroupName = "GroupFoo"; // Value not used
scoped_refptr<base::FieldTrial> trial =
base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
std::map<std::string, std::string> params;
if (GetParam()) {
params["web_effective_connection_type_override"] = "2G";
}
ASSERT_TRUE(
base::FieldTrialParamAssociator::GetInstance()
->AssociateFieldTrialParams(kTrialName, kGroupName, params));
std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
feature_list->RegisterFieldTrialOverride(
features::kNetworkQualityEstimatorWebHoldback.name,
base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
}
// Simulates a network quality change.
void SimulateNetworkQualityChange(net::EffectiveConnectionType type) {
if (network_service_enabled_)
return;
content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE,
base::BindOnce(&SimulateNetworkQualityChangeOnIO, type));
}
bool network_service_enabled() const { return network_service_enabled_; }
private:
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::TimeDelta::FromMilliseconds(3000))
expected_rtt = base::TimeDelta::FromMilliseconds(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));
}
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));
}
std::string RunScriptExtractString(const std::string& script) {
std::string data;
EXPECT_TRUE(content::ExecuteScriptAndExtractString(
browser()->tab_strip_model()->GetActiveWebContents(), script, &data));
return data;
}
double RunScriptExtractDouble(const std::string& script) {
double data = 0.0;
EXPECT_TRUE(ExecuteScriptAndExtractDouble(
browser()->tab_strip_model()->GetActiveWebContents(), script, &data));
return data;
}
int RunScriptExtractInt(const std::string& script) {
int data = 0;
EXPECT_TRUE(ExecuteScriptAndExtractInt(
browser()->tab_strip_model()->GetActiveWebContents(), script, &data));
return data;
}
net::EmbeddedTestServer test_server_;
base::test::ScopedFeatureList scoped_feature_list_;
const bool network_service_enabled_;
};
// Make sure the changes in the effective connection typeare notified to the
// render thread.
IN_PROC_BROWSER_TEST_P(NetInfoNetworkQualityEstimatorHoldbackBrowserTest,
EffectiveConnectionTypeChangeNotified) {
// When network service is enabled, and the holdback experiment is disabled,
// the test fails.
if (network_service_enabled() && !GetParam())
return;
SimulateNetworkQualityChange(net::EFFECTIVE_CONNECTION_TYPE_3G);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(embedded_test_server()->Start());
ui_test_utils::NavigateToURL(
browser(), embedded_test_server()->GetURL("/net_info.html"));
if (GetParam()) {
// ConfigureHoldbackExperiment() sets holdback ECT to 2G.
VerifyNetworkQualityNetInfoWebAPI("2g");
} else {
VerifyNetworkQualityNetInfoWebAPI("3g");
}
SimulateNetworkQualityChange(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
base::RunLoop().RunUntilIdle();
if (GetParam()) {
// ConfigureHoldbackExperiment() sets holdback ECT to 2G.
VerifyNetworkQualityNetInfoWebAPI("2g");
} else {
VerifyNetworkQualityNetInfoWebAPI("slow-2g");
}
}
// The network quality estimator web holdback is enabled only if the first
// param is true.
INSTANTIATE_TEST_CASE_P(,
NetInfoNetworkQualityEstimatorHoldbackBrowserTest,
testing::Bool());
...@@ -662,6 +662,7 @@ test("browser_tests") { ...@@ -662,6 +662,7 @@ test("browser_tests") {
"../browser/net/errorpage_browsertest.cc", "../browser/net/errorpage_browsertest.cc",
"../browser/net/ftp_browsertest.cc", "../browser/net/ftp_browsertest.cc",
"../browser/net/load_timing_browsertest.cc", "../browser/net/load_timing_browsertest.cc",
"../browser/net/netinfo_network_quality_estimator_holdback_browsertest.cc",
"../browser/net/network_connection_tracker_browsertest.cc", "../browser/net/network_connection_tracker_browsertest.cc",
"../browser/net/network_context_configuration_browsertest.cc", "../browser/net/network_context_configuration_browsertest.cc",
"../browser/net/network_quality_tracker_browsertest.cc", "../browser/net/network_quality_tracker_browsertest.cc",
......
...@@ -237,7 +237,7 @@ IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, ...@@ -237,7 +237,7 @@ IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest,
// Make sure the changes in the effective connection typeare notified to the // Make sure the changes in the effective connection typeare notified to the
// render thread. // render thread.
IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest, IN_PROC_BROWSER_TEST_F(NetInfoBrowserTest,
EffectiveConnectionTypeChangeNotfied) { EffectiveConnectionTypeChangeNotified) {
base::HistogramTester histogram_tester; base::HistogramTester histogram_tester;
net::TestNetworkQualityEstimator estimator( net::TestNetworkQualityEstimator estimator(
std::map<std::string, std::string>(), false, false, true, std::map<std::string, std::string>(), false, false, true,
......
...@@ -239,6 +239,7 @@ IPC_STRUCT_TRAITS_BEGIN(content::WebPreferences) ...@@ -239,6 +239,7 @@ IPC_STRUCT_TRAITS_BEGIN(content::WebPreferences)
IPC_STRUCT_TRAITS_MEMBER(low_priority_iframes_threshold) IPC_STRUCT_TRAITS_MEMBER(low_priority_iframes_threshold)
IPC_STRUCT_TRAITS_MEMBER(picture_in_picture_enabled) IPC_STRUCT_TRAITS_MEMBER(picture_in_picture_enabled)
IPC_STRUCT_TRAITS_MEMBER(translate_service_available) IPC_STRUCT_TRAITS_MEMBER(translate_service_available)
IPC_STRUCT_TRAITS_MEMBER(network_quality_estimator_web_holdback)
IPC_STRUCT_TRAITS_MEMBER(lazy_frame_loading_distance_thresholds_px) IPC_STRUCT_TRAITS_MEMBER(lazy_frame_loading_distance_thresholds_px)
IPC_STRUCT_TRAITS_END() IPC_STRUCT_TRAITS_END()
......
...@@ -165,6 +165,12 @@ const base::Feature kGamepadExtensions{"GamepadExtensions", ...@@ -165,6 +165,12 @@ const base::Feature kGamepadExtensions{"GamepadExtensions",
const base::Feature kGamepadVibration{"GamepadVibration", const base::Feature kGamepadVibration{"GamepadVibration",
base::FEATURE_ENABLED_BY_DEFAULT}; base::FEATURE_ENABLED_BY_DEFAULT};
// Puts network quality estimate related Web APIs in the holdback mode. When the
// holdback is enabled the related Web APIs return network quality estimate
// set by the experiment (regardless of the actual quality).
const base::Feature kNetworkQualityEstimatorWebHoldback{
"NetworkQualityEstimatorWebHoldback", base::FEATURE_DISABLED_BY_DEFAULT};
// When WebXR Device API is enabled, exposes VR controllers as Gamepads and // When WebXR Device API is enabled, exposes VR controllers as Gamepads and
// enables additional Gamepad attributes for use with WebXR Device API. Each // enables additional Gamepad attributes for use with WebXR Device API. Each
// XRInputSource will have a corresponding Gamepad instance. // XRInputSource will have a corresponding Gamepad instance.
......
...@@ -70,6 +70,7 @@ CONTENT_EXPORT extern const base::Feature kModuleScriptsImportMetaUrl; ...@@ -70,6 +70,7 @@ CONTENT_EXPORT extern const base::Feature kModuleScriptsImportMetaUrl;
CONTENT_EXPORT extern const base::Feature kMojoSessionStorage; CONTENT_EXPORT extern const base::Feature kMojoSessionStorage;
CONTENT_EXPORT extern const base::Feature kMojoVideoCapture; CONTENT_EXPORT extern const base::Feature kMojoVideoCapture;
CONTENT_EXPORT extern const base::Feature kMojoVideoCaptureSecondary; CONTENT_EXPORT extern const base::Feature kMojoVideoCaptureSecondary;
CONTENT_EXPORT extern const base::Feature kNetworkQualityEstimatorWebHoldback;
CONTENT_EXPORT extern const base::Feature kNetworkServiceInProcess; CONTENT_EXPORT extern const base::Feature kNetworkServiceInProcess;
CONTENT_EXPORT extern const base::Feature kNotificationContentImage; CONTENT_EXPORT extern const base::Feature kNotificationContentImage;
CONTENT_EXPORT extern const base::Feature kOriginPolicy; CONTENT_EXPORT extern const base::Feature kOriginPolicy;
......
...@@ -236,7 +236,9 @@ WebPreferences::WebPreferences() ...@@ -236,7 +236,9 @@ WebPreferences::WebPreferences()
autoplay_policy(AutoplayPolicy::kDocumentUserActivationRequired), autoplay_policy(AutoplayPolicy::kDocumentUserActivationRequired),
low_priority_iframes_threshold(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN), low_priority_iframes_threshold(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
picture_in_picture_enabled(true), picture_in_picture_enabled(true),
translate_service_available(false) { translate_service_available(false),
network_quality_estimator_web_holdback(
net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
standard_font_family_map[kCommonScript] = standard_font_family_map[kCommonScript] =
base::ASCIIToUTF16("Times New Roman"); base::ASCIIToUTF16("Times New Roman");
fixed_font_family_map[kCommonScript] = base::ASCIIToUTF16("Courier New"); fixed_font_family_map[kCommonScript] = base::ASCIIToUTF16("Courier New");
......
...@@ -308,6 +308,13 @@ struct CONTENT_EXPORT WebPreferences { ...@@ -308,6 +308,13 @@ struct CONTENT_EXPORT WebPreferences {
// See https://github.com/dtapuska/html-translate // See https://github.com/dtapuska/html-translate
bool translate_service_available; bool translate_service_available;
// A value other than net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN implies that the
// network quality estimate related Web APIs are in the holdback mode. When
// the holdback is enabled, the related Web APIs return network quality
// estimate corresponding to |network_quality_estimator_web_holdback|
// regardless of the actual quality.
net::EffectiveConnectionType network_quality_estimator_web_holdback;
// Specifies how close a lazily loaded iframe or image should be from the // Specifies how close a lazily loaded iframe or image should be from the
// viewport before it should start being loaded in, depending on the effective // viewport before it should start being loaded in, depending on the effective
// connection type of the current network. Blink will use the default distance // connection type of the current network. Blink will use the default distance
......
...@@ -816,6 +816,9 @@ void RenderView::ApplyWebPreferences(const WebPreferences& prefs, ...@@ -816,6 +816,9 @@ void RenderView::ApplyWebPreferences(const WebPreferences& prefs,
settings->SetTextAutosizingEnabled(prefs.text_autosizing_enabled); settings->SetTextAutosizingEnabled(prefs.text_autosizing_enabled);
settings->SetDoubleTapToZoomEnabled(prefs.double_tap_to_zoom_enabled); settings->SetDoubleTapToZoomEnabled(prefs.double_tap_to_zoom_enabled);
blink::WebNetworkStateNotifier::SetNetworkQualityWebHoldback(
static_cast<blink::WebEffectiveConnectionType>(
prefs.network_quality_estimator_web_holdback));
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
settings->SetAllowCustomScrollbarInMainFrame(false); settings->SetAllowCustomScrollbarInMainFrame(false);
......
...@@ -48,6 +48,8 @@ class WebNetworkStateNotifier { ...@@ -48,6 +48,8 @@ class WebNetworkStateNotifier {
base::TimeDelta http_rtt, base::TimeDelta http_rtt,
base::TimeDelta transport_rtt, base::TimeDelta transport_rtt,
int downlink_throughput_kbps); int downlink_throughput_kbps);
BLINK_PLATFORM_EXPORT static void SetNetworkQualityWebHoldback(
WebEffectiveConnectionType);
BLINK_PLATFORM_EXPORT static void SetSaveDataEnabled(bool enabled); BLINK_PLATFORM_EXPORT static void SetSaveDataEnabled(bool enabled);
private: private:
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#include "third_party/blink/renderer/core/dom/events/event.h" #include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/settings.h" #include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/inspector/console_types.h"
#include "third_party/blink/renderer/modules/event_target_modules.h" #include "third_party/blink/renderer/modules/event_target_modules.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
...@@ -64,6 +66,11 @@ String ConnectionTypeToString(WebConnectionType type) { ...@@ -64,6 +66,11 @@ String ConnectionTypeToString(WebConnectionType type) {
return "none"; return "none";
} }
String GetConsoleLogStringForWebHoldback() {
return "Network quality values are overridden using a holdback experiment, "
"and so may be inaccurate";
}
} // namespace } // namespace
NetworkInformation* NetworkInformation::Create(ExecutionContext* context) { NetworkInformation* NetworkInformation::Create(ExecutionContext* context) {
...@@ -95,7 +102,15 @@ double NetworkInformation::downlinkMax() const { ...@@ -95,7 +102,15 @@ double NetworkInformation::downlinkMax() const {
return downlink_max_mbps_; return downlink_max_mbps_;
} }
String NetworkInformation::effectiveType() const { String NetworkInformation::effectiveType() {
MaybeShowWebHoldbackConsoleMsg();
base::Optional<WebEffectiveConnectionType> override_ect =
GetNetworkStateNotifier().GetWebHoldbackEffectiveType();
if (override_ect) {
return NetworkStateNotifier::EffectiveConnectionTypeToString(
override_ect.value());
}
// effective_type_ is only updated when listening for events, so ask // effective_type_ is only updated when listening for events, so ask
// networkStateNotifier if not listening (crbug.com/379841). // networkStateNotifier if not listening (crbug.com/379841).
if (!IsObserving()) { if (!IsObserving()) {
...@@ -107,7 +122,14 @@ String NetworkInformation::effectiveType() const { ...@@ -107,7 +122,14 @@ String NetworkInformation::effectiveType() const {
return NetworkStateNotifier::EffectiveConnectionTypeToString(effective_type_); return NetworkStateNotifier::EffectiveConnectionTypeToString(effective_type_);
} }
unsigned long NetworkInformation::rtt() const { unsigned long NetworkInformation::rtt() {
MaybeShowWebHoldbackConsoleMsg();
base::Optional<TimeDelta> override_rtt =
GetNetworkStateNotifier().GetWebHoldbackHttpRtt();
if (override_rtt) {
return GetNetworkStateNotifier().RoundRtt(Host(), override_rtt.value());
}
if (!IsObserving()) { if (!IsObserving()) {
return GetNetworkStateNotifier().RoundRtt( return GetNetworkStateNotifier().RoundRtt(
Host(), GetNetworkStateNotifier().HttpRtt()); Host(), GetNetworkStateNotifier().HttpRtt());
...@@ -116,7 +138,15 @@ unsigned long NetworkInformation::rtt() const { ...@@ -116,7 +138,15 @@ unsigned long NetworkInformation::rtt() const {
return http_rtt_msec_; return http_rtt_msec_;
} }
double NetworkInformation::downlink() const { double NetworkInformation::downlink() {
MaybeShowWebHoldbackConsoleMsg();
base::Optional<double> override_downlink_mbps =
GetNetworkStateNotifier().GetWebHoldbackDownlinkThroughputMbps();
if (override_downlink_mbps) {
return GetNetworkStateNotifier().RoundMbps(Host(),
override_downlink_mbps.value());
}
if (!IsObserving()) { if (!IsObserving()) {
return GetNetworkStateNotifier().RoundMbps( return GetNetworkStateNotifier().RoundMbps(
Host(), GetNetworkStateNotifier().DownlinkThroughputMbps()); Host(), GetNetworkStateNotifier().DownlinkThroughputMbps());
...@@ -148,20 +178,27 @@ void NetworkInformation::ConnectionChange( ...@@ -148,20 +178,27 @@ void NetworkInformation::ConnectionChange(
double new_downlink_mbps = double new_downlink_mbps =
GetNetworkStateNotifier().RoundMbps(host, downlink_mbps); GetNetworkStateNotifier().RoundMbps(host, downlink_mbps);
bool network_quality_estimate_changed = false;
// Allow setting |network_quality_estimate_changed| to true only if the
// network quality holdback experiment is not enabled.
if (!GetNetworkStateNotifier().GetWebHoldbackEffectiveType()) {
network_quality_estimate_changed = effective_type_ != effective_type ||
http_rtt_msec_ != new_http_rtt_msec ||
downlink_mbps_ != new_downlink_mbps;
}
// This can happen if the observer removes and then adds itself again // This can happen if the observer removes and then adds itself again
// during notification, or if |transport_rtt| was the only metric that // during notification, or if |transport_rtt| was the only metric that
// changed. // changed.
if (type_ == type && downlink_max_mbps_ == downlink_max_mbps && if (type_ == type && downlink_max_mbps_ == downlink_max_mbps &&
effective_type_ == effective_type && !network_quality_estimate_changed && save_data_ == save_data) {
http_rtt_msec_ == new_http_rtt_msec &&
downlink_mbps_ == new_downlink_mbps && save_data_ == save_data) {
return; return;
} }
// If the NetInfoDownlinkMaxEnabled is not enabled, then |type| and
// |downlink_max_mbps| should not be checked for change.
if (!RuntimeEnabledFeatures::NetInfoDownlinkMaxEnabled() && if (!RuntimeEnabledFeatures::NetInfoDownlinkMaxEnabled() &&
effective_type_ == effective_type && !network_quality_estimate_changed && save_data_ == save_data) {
http_rtt_msec_ == new_http_rtt_msec &&
downlink_mbps_ == new_downlink_mbps && save_data_ == save_data) {
return; return;
} }
...@@ -171,9 +208,11 @@ void NetworkInformation::ConnectionChange( ...@@ -171,9 +208,11 @@ void NetworkInformation::ConnectionChange(
type_ = type; type_ = type;
downlink_max_mbps_ = downlink_max_mbps; downlink_max_mbps_ = downlink_max_mbps;
if (network_quality_estimate_changed) {
effective_type_ = effective_type; effective_type_ = effective_type;
http_rtt_msec_ = new_http_rtt_msec; http_rtt_msec_ = new_http_rtt_msec;
downlink_mbps_ = new_downlink_mbps; downlink_mbps_ = new_downlink_mbps;
}
save_data_ = save_data; save_data_ = save_data;
if (type_changed) if (type_changed)
...@@ -194,6 +233,7 @@ void NetworkInformation::AddedEventListener( ...@@ -194,6 +233,7 @@ void NetworkInformation::AddedEventListener(
RegisteredEventListener& registered_listener) { RegisteredEventListener& registered_listener) {
EventTargetWithInlineData::AddedEventListener(event_type, EventTargetWithInlineData::AddedEventListener(event_type,
registered_listener); registered_listener);
MaybeShowWebHoldbackConsoleMsg();
StartObserving(); StartObserving();
} }
...@@ -243,18 +283,20 @@ void NetworkInformation::StopObserving() { ...@@ -243,18 +283,20 @@ void NetworkInformation::StopObserving() {
NetworkInformation::NetworkInformation(ExecutionContext* context) NetworkInformation::NetworkInformation(ExecutionContext* context)
: ContextLifecycleObserver(context), : ContextLifecycleObserver(context),
type_(GetNetworkStateNotifier().ConnectionType()), web_holdback_console_message_shown_(false),
downlink_max_mbps_(GetNetworkStateNotifier().MaxBandwidth()),
effective_type_(GetNetworkStateNotifier().EffectiveType()),
http_rtt_msec_(GetNetworkStateNotifier().RoundRtt(
Host(),
GetNetworkStateNotifier().HttpRtt())),
downlink_mbps_(GetNetworkStateNotifier().RoundMbps(
Host(),
GetNetworkStateNotifier().DownlinkThroughputMbps())),
save_data_(GetNetworkStateNotifier().SaveDataEnabled() &&
!IsInDataSaverHoldbackWebApi(GetExecutionContext())),
context_stopped_(false) { context_stopped_(false) {
base::Optional<TimeDelta> http_rtt;
base::Optional<double> downlink_mbps;
GetNetworkStateNotifier().GetMetricsWithWebHoldback(
&type_, &downlink_max_mbps_, &effective_type_, &http_rtt, &downlink_mbps,
&save_data_);
http_rtt_msec_ = GetNetworkStateNotifier().RoundRtt(Host(), http_rtt);
downlink_mbps_ = GetNetworkStateNotifier().RoundMbps(Host(), downlink_mbps);
save_data_ =
save_data_ && !IsInDataSaverHoldbackWebApi(GetExecutionContext());
DCHECK_LE(1u, GetNetworkStateNotifier().RandomizationSalt()); DCHECK_LE(1u, GetNetworkStateNotifier().RandomizationSalt());
DCHECK_GE(20u, GetNetworkStateNotifier().RandomizationSalt()); DCHECK_GE(20u, GetNetworkStateNotifier().RandomizationSalt());
} }
...@@ -268,4 +310,15 @@ const String NetworkInformation::Host() const { ...@@ -268,4 +310,15 @@ const String NetworkInformation::Host() const {
return GetExecutionContext() ? GetExecutionContext()->Url().Host() : String(); return GetExecutionContext() ? GetExecutionContext()->Url().Host() : String();
} }
void NetworkInformation::MaybeShowWebHoldbackConsoleMsg() {
if (web_holdback_console_message_shown_)
return;
web_holdback_console_message_shown_ = true;
if (!GetNetworkStateNotifier().GetWebHoldbackEffectiveType())
return;
GetExecutionContext()->AddConsoleMessage(
ConsoleMessage::Create(kOtherMessageSource, kWarningMessageLevel,
GetConsoleLogStringForWebHoldback()));
}
} // namespace blink } // namespace blink
...@@ -32,9 +32,9 @@ class NetworkInformation final ...@@ -32,9 +32,9 @@ class NetworkInformation final
String type() const; String type() const;
double downlinkMax() const; double downlinkMax() const;
String effectiveType() const; String effectiveType();
unsigned long rtt() const; unsigned long rtt();
double downlink() const; double downlink();
bool saveData() const; bool saveData() const;
// NetworkStateObserver overrides. // NetworkStateObserver overrides.
...@@ -79,6 +79,8 @@ class NetworkInformation final ...@@ -79,6 +79,8 @@ class NetworkInformation final
const String Host() const; const String Host() const;
void MaybeShowWebHoldbackConsoleMsg();
// Touched only on context thread. // Touched only on context thread.
WebConnectionType type_; WebConnectionType type_;
...@@ -101,6 +103,11 @@ class NetworkInformation final ...@@ -101,6 +103,11 @@ class NetworkInformation final
// Whether the data saving mode is enabled. // Whether the data saving mode is enabled.
bool save_data_; bool save_data_;
// True if the console message indicating that network quality is overridden
// using a holdback experiment has been shown. Set to true if the console
// message has been shown, or if the holdback experiment is not enabled.
bool web_holdback_console_message_shown_;
// Whether ContextLifecycleObserver::contextDestroyed has been called. // Whether ContextLifecycleObserver::contextDestroyed has been called.
bool context_stopped_; bool context_stopped_;
......
...@@ -51,6 +51,11 @@ void WebNetworkStateNotifier::SetNetworkQuality(WebEffectiveConnectionType type, ...@@ -51,6 +51,11 @@ void WebNetworkStateNotifier::SetNetworkQuality(WebEffectiveConnectionType type,
downlink_throughput_kbps); downlink_throughput_kbps);
} }
void WebNetworkStateNotifier::SetNetworkQualityWebHoldback(
WebEffectiveConnectionType type) {
GetNetworkStateNotifier().SetNetworkQualityWebHoldback(type);
}
void WebNetworkStateNotifier::SetSaveDataEnabled(bool enabled) { void WebNetworkStateNotifier::SetSaveDataEnabled(bool enabled) {
GetNetworkStateNotifier().SetSaveDataEnabled(enabled); GetNetworkStateNotifier().SetSaveDataEnabled(enabled);
} }
......
...@@ -40,6 +40,29 @@ ...@@ -40,6 +40,29 @@
namespace blink { namespace blink {
namespace {
// Typical HTTP RTT value corresponding to a given WebEffectiveConnectionType
// value. Taken from
// https://cs.chromium.org/chromium/src/net/nqe/network_quality_estimator_params.cc.
const base::TimeDelta kTypicalHttpRttEffectiveConnectionType
[static_cast<size_t>(WebEffectiveConnectionType::kMaxValue) + 1] = {
base::TimeDelta::FromMilliseconds(0),
base::TimeDelta::FromMilliseconds(0),
base::TimeDelta::FromMilliseconds(3600),
base::TimeDelta::FromMilliseconds(1800),
base::TimeDelta::FromMilliseconds(450),
base::TimeDelta::FromMilliseconds(175)};
// Typical downlink throughput (in Mbps) value corresponding to a given
// WebEffectiveConnectionType value. Taken from
// https://cs.chromium.org/chromium/src/net/nqe/network_quality_estimator_params.cc.
const double kTypicalDownlinkMbpsEffectiveConnectionType
[static_cast<size_t>(WebEffectiveConnectionType::kMaxValue) + 1] = {
0, 0, 0.040, 0.075, 0.400, 1.600};
} // namespace
template <> template <>
struct CrossThreadCopier<NetworkStateNotifier::NetworkState> struct CrossThreadCopier<NetworkStateNotifier::NetworkState>
: public CrossThreadCopierPassThrough<NetworkStateNotifier::NetworkState> { : public CrossThreadCopierPassThrough<NetworkStateNotifier::NetworkState> {
...@@ -144,6 +167,19 @@ void NetworkStateNotifier::SetNetworkQuality(WebEffectiveConnectionType type, ...@@ -144,6 +167,19 @@ void NetworkStateNotifier::SetNetworkQuality(WebEffectiveConnectionType type,
} }
} }
void NetworkStateNotifier::SetNetworkQualityWebHoldback(
WebEffectiveConnectionType type) {
DCHECK(IsMainThread());
if (type == WebEffectiveConnectionType::kTypeUnknown)
return;
ScopedNotifier notifier(*this);
{
MutexLocker locker(mutex_);
state_.network_quality_web_holdback = type;
}
}
std::unique_ptr<NetworkStateNotifier::NetworkStateObserverHandle> std::unique_ptr<NetworkStateNotifier::NetworkStateObserverHandle>
NetworkStateNotifier::AddConnectionObserver( NetworkStateNotifier::AddConnectionObserver(
NetworkStateObserver* observer, NetworkStateObserver* observer,
...@@ -448,4 +484,67 @@ double NetworkStateNotifier::RoundMbps( ...@@ -448,4 +484,67 @@ double NetworkStateNotifier::RoundMbps(
return downlink_kbps_rounded / 1000; return downlink_kbps_rounded / 1000;
} }
base::Optional<WebEffectiveConnectionType>
NetworkStateNotifier::GetWebHoldbackEffectiveType() const {
MutexLocker locker(mutex_);
const NetworkState& state = has_override_ ? override_ : state_;
// TODO (tbansal): Add a DCHECK to check that |state.on_line_initialized| is
// true once https://crbug.com/728771 is fixed.
return state.network_quality_web_holdback;
}
base::Optional<TimeDelta> NetworkStateNotifier::GetWebHoldbackHttpRtt() const {
base::Optional<WebEffectiveConnectionType> override_ect =
GetWebHoldbackEffectiveType();
if (override_ect) {
return kTypicalHttpRttEffectiveConnectionType[static_cast<size_t>(
override_ect.value())];
}
return base::nullopt;
}
base::Optional<double>
NetworkStateNotifier::GetWebHoldbackDownlinkThroughputMbps() const {
base::Optional<WebEffectiveConnectionType> override_ect =
GetWebHoldbackEffectiveType();
if (override_ect) {
return kTypicalDownlinkMbpsEffectiveConnectionType[static_cast<size_t>(
override_ect.value())];
}
return base::nullopt;
}
void NetworkStateNotifier::GetMetricsWithWebHoldback(
WebConnectionType* type,
double* downlink_max_mbps,
WebEffectiveConnectionType* effective_type,
base::Optional<TimeDelta>* http_rtt,
base::Optional<double>* downlink_mbps,
bool* save_data) const {
MutexLocker locker(mutex_);
const NetworkState& state = has_override_ ? override_ : state_;
*type = state.type;
*downlink_max_mbps = state.max_bandwidth_mbps;
base::Optional<WebEffectiveConnectionType> override_ect =
state.network_quality_web_holdback;
if (override_ect) {
*effective_type = override_ect.value();
*http_rtt = kTypicalHttpRttEffectiveConnectionType[static_cast<size_t>(
override_ect.value())];
*downlink_mbps =
kTypicalDownlinkMbpsEffectiveConnectionType[static_cast<size_t>(
override_ect.value())];
} else {
*effective_type = state.effective_type;
*http_rtt = state.http_rtt;
*downlink_mbps = state.downlink_throughput_mbps;
}
*save_data = state.save_data;
}
} // namespace blink } // namespace blink
...@@ -63,6 +63,12 @@ class PLATFORM_EXPORT NetworkStateNotifier { ...@@ -63,6 +63,12 @@ class PLATFORM_EXPORT NetworkStateNotifier {
base::Optional<TimeDelta> transport_rtt; base::Optional<TimeDelta> transport_rtt;
base::Optional<double> downlink_throughput_mbps; base::Optional<double> downlink_throughput_mbps;
bool save_data = false; bool save_data = false;
// If set, then network quality corresponding to
// |network_quality_web_holdback| should be returned to the web consumers.
// Consumers within Blink should still receive the actual network quality
// values.
base::Optional<WebEffectiveConnectionType> network_quality_web_holdback;
}; };
class NetworkStateObserver { class NetworkStateObserver {
...@@ -212,6 +218,7 @@ class PLATFORM_EXPORT NetworkStateNotifier { ...@@ -212,6 +218,7 @@ class PLATFORM_EXPORT NetworkStateNotifier {
TimeDelta http_rtt, TimeDelta http_rtt,
TimeDelta transport_rtt, TimeDelta transport_rtt,
int downlink_throughput_kbps); int downlink_throughput_kbps);
void SetNetworkQualityWebHoldback(WebEffectiveConnectionType);
void SetSaveDataEnabled(bool enabled); void SetSaveDataEnabled(bool enabled);
// When called, successive setWebConnectionType/setOnLine calls are stored, // When called, successive setWebConnectionType/setOnLine calls are stored,
...@@ -263,6 +270,35 @@ class PLATFORM_EXPORT NetworkStateNotifier { ...@@ -263,6 +270,35 @@ class PLATFORM_EXPORT NetworkStateNotifier {
// amount of noise for a given origin. // amount of noise for a given origin.
uint8_t RandomizationSalt() const { return randomization_salt_; } uint8_t RandomizationSalt() const { return randomization_salt_; }
// Returns the overriding effective connection type that should be returned to
// the web consumers. If the returned value is null, then the actual network
// quality value should be returned to the web consumers.
// Consumers within Blink should not call this API.
base::Optional<WebEffectiveConnectionType> GetWebHoldbackEffectiveType()
const;
// Returns the overriding HTTP RTT estimate that should be returned to
// the web consumers. If the returned value is null, then the actual network
// quality value should be returned to the web consumers.
// Consumers within Blink should not call this API.
base::Optional<TimeDelta> GetWebHoldbackHttpRtt() const;
// Returns the overriding HTTP RTT estimate that should be returned to
// the web consumers. If the returned value is null, then the actual network
// quality value should be returned to the web consumers.
// Consumers within Blink should not call this API.
base::Optional<double> GetWebHoldbackDownlinkThroughputMbps() const;
// Sets the metrics of all the values while taking into account any network
// quality web holdbacks in place. The caller must guarantee that all pointers
// are non-null.
void GetMetricsWithWebHoldback(WebConnectionType* type,
double* downlink_max_mbps,
WebEffectiveConnectionType* effective_type,
base::Optional<TimeDelta>* http_rtt,
base::Optional<double>* downlink_mbps,
bool* save_data) const;
private: private:
friend class NetworkStateObserverHandle; friend class NetworkStateObserverHandle;
......
...@@ -217,6 +217,32 @@ class NetworkStateNotifierTest : public testing::Test { ...@@ -217,6 +217,32 @@ class NetworkStateNotifierTest : public testing::Test {
RunPendingTasks(); RunPendingTasks();
} }
void VerifyInitialMetricsWithWebHoldbackState(
WebConnectionType expected_type,
double expected_max_bandwidth_mbps,
WebEffectiveConnectionType expected_effective_type,
const base::Optional<TimeDelta>& expected_http_rtt,
const base::Optional<double>& expected_downlink_throughput_mbps,
SaveData expected_save_data) const {
WebConnectionType initial_type;
double initial_downlink_max_mbps;
WebEffectiveConnectionType initial_effective_type;
base::Optional<TimeDelta> initial_http_rtt;
base::Optional<double> initial_downlink_mbps;
bool initial_save_data;
notifier_.GetMetricsWithWebHoldback(
&initial_type, &initial_downlink_max_mbps, &initial_effective_type,
&initial_http_rtt, &initial_downlink_mbps, &initial_save_data);
EXPECT_EQ(expected_type, initial_type);
EXPECT_EQ(expected_max_bandwidth_mbps, initial_downlink_max_mbps);
EXPECT_EQ(expected_effective_type, initial_effective_type);
EXPECT_EQ(expected_http_rtt, initial_http_rtt);
EXPECT_EQ(expected_downlink_throughput_mbps, initial_downlink_mbps);
EXPECT_EQ(expected_save_data == SaveData::kOn, initial_save_data);
}
bool VerifyObservations( bool VerifyObservations(
const StateObserver& observer, const StateObserver& observer,
WebConnectionType type, WebConnectionType type,
...@@ -259,6 +285,11 @@ TEST_F(NetworkStateNotifierTest, AddObserver) { ...@@ -259,6 +285,11 @@ TEST_F(NetworkStateNotifierTest, AddObserver) {
WebEffectiveConnectionType::kTypeUnknown, kUnknownRtt, kUnknownRtt, WebEffectiveConnectionType::kTypeUnknown, kUnknownRtt, kUnknownRtt,
kUnknownThroughputMbps, SaveData::kOff)); kUnknownThroughputMbps, SaveData::kOff));
VerifyInitialMetricsWithWebHoldbackState(
kWebConnectionTypeUnknown, kNoneMaxBandwidthMbps,
WebEffectiveConnectionType::kTypeUnknown, kUnknownRtt,
kUnknownThroughputMbps, SaveData::kOff);
// Change max. bandwidth and the network quality estimates. // Change max. bandwidth and the network quality estimates.
SetConnection(kWebConnectionTypeBluetooth, kBluetoothMaxBandwidthMbps, SetConnection(kWebConnectionTypeBluetooth, kBluetoothMaxBandwidthMbps,
WebEffectiveConnectionType::kType3G, kEthernetHttpRtt, WebEffectiveConnectionType::kType3G, kEthernetHttpRtt,
...@@ -269,6 +300,11 @@ TEST_F(NetworkStateNotifierTest, AddObserver) { ...@@ -269,6 +300,11 @@ TEST_F(NetworkStateNotifierTest, AddObserver) {
kEthernetTransportRtt, kEthernetThroughputMbps, SaveData::kOff)); kEthernetTransportRtt, kEthernetThroughputMbps, SaveData::kOff));
EXPECT_EQ(observer.CallbackCount(), 2); EXPECT_EQ(observer.CallbackCount(), 2);
VerifyInitialMetricsWithWebHoldbackState(
kWebConnectionTypeBluetooth, kBluetoothMaxBandwidthMbps,
WebEffectiveConnectionType::kType3G, kEthernetHttpRtt,
kEthernetThroughputMbps, SaveData::kOff);
// Only change the connection type. // Only change the connection type.
SetConnection(kWebConnectionTypeEthernet, kBluetoothMaxBandwidthMbps, SetConnection(kWebConnectionTypeEthernet, kBluetoothMaxBandwidthMbps,
WebEffectiveConnectionType::kType3G, kEthernetHttpRtt, WebEffectiveConnectionType::kType3G, kEthernetHttpRtt,
...@@ -571,6 +607,10 @@ TEST_F(NetworkStateNotifierTest, SetNetworkConnectionInfoOverride) { ...@@ -571,6 +607,10 @@ TEST_F(NetworkStateNotifierTest, SetNetworkConnectionInfoOverride) {
EXPECT_TRUE(notifier_.OnLine()); EXPECT_TRUE(notifier_.OnLine());
EXPECT_EQ(kWebConnectionTypeBluetooth, notifier_.ConnectionType()); EXPECT_EQ(kWebConnectionTypeBluetooth, notifier_.ConnectionType());
EXPECT_EQ(kBluetoothMaxBandwidthMbps, notifier_.MaxBandwidth()); EXPECT_EQ(kBluetoothMaxBandwidthMbps, notifier_.MaxBandwidth());
VerifyInitialMetricsWithWebHoldbackState(
kWebConnectionTypeBluetooth, kBluetoothMaxBandwidthMbps,
WebEffectiveConnectionType::kTypeUnknown, kUnknownRtt,
kUnknownThroughputMbps, SaveData::kOff);
notifier_.SetNetworkConnectionInfoOverride( notifier_.SetNetworkConnectionInfoOverride(
true, kWebConnectionTypeEthernet, WebEffectiveConnectionType::kType4G, true, kWebConnectionTypeEthernet, WebEffectiveConnectionType::kType4G,
...@@ -583,6 +623,10 @@ TEST_F(NetworkStateNotifierTest, SetNetworkConnectionInfoOverride) { ...@@ -583,6 +623,10 @@ TEST_F(NetworkStateNotifierTest, SetNetworkConnectionInfoOverride) {
EXPECT_TRUE(notifier_.OnLine()); EXPECT_TRUE(notifier_.OnLine());
EXPECT_EQ(kWebConnectionTypeEthernet, notifier_.ConnectionType()); EXPECT_EQ(kWebConnectionTypeEthernet, notifier_.ConnectionType());
EXPECT_EQ(kEthernetMaxBandwidthMbps, notifier_.MaxBandwidth()); EXPECT_EQ(kEthernetMaxBandwidthMbps, notifier_.MaxBandwidth());
VerifyInitialMetricsWithWebHoldbackState(
kWebConnectionTypeEthernet, kEthernetMaxBandwidthMbps,
WebEffectiveConnectionType::kType4G, kEthernetHttpRtt,
kEthernetMaxBandwidthMbps, SaveData::kOff);
// When override is active, calls to setOnLine and setConnection are temporary // When override is active, calls to setOnLine and setConnection are temporary
// ignored. // ignored.
...@@ -598,6 +642,10 @@ TEST_F(NetworkStateNotifierTest, SetNetworkConnectionInfoOverride) { ...@@ -598,6 +642,10 @@ TEST_F(NetworkStateNotifierTest, SetNetworkConnectionInfoOverride) {
EXPECT_TRUE(notifier_.OnLine()); EXPECT_TRUE(notifier_.OnLine());
EXPECT_EQ(kWebConnectionTypeEthernet, notifier_.ConnectionType()); EXPECT_EQ(kWebConnectionTypeEthernet, notifier_.ConnectionType());
EXPECT_EQ(kEthernetMaxBandwidthMbps, notifier_.MaxBandwidth()); EXPECT_EQ(kEthernetMaxBandwidthMbps, notifier_.MaxBandwidth());
VerifyInitialMetricsWithWebHoldbackState(
kWebConnectionTypeEthernet, kEthernetMaxBandwidthMbps,
WebEffectiveConnectionType::kType4G, kEthernetHttpRtt,
kEthernetMaxBandwidthMbps, SaveData::kOff);
notifier_.ClearOverride(); notifier_.ClearOverride();
RunPendingTasks(); RunPendingTasks();
...@@ -608,6 +656,10 @@ TEST_F(NetworkStateNotifierTest, SetNetworkConnectionInfoOverride) { ...@@ -608,6 +656,10 @@ TEST_F(NetworkStateNotifierTest, SetNetworkConnectionInfoOverride) {
EXPECT_FALSE(notifier_.OnLine()); EXPECT_FALSE(notifier_.OnLine());
EXPECT_EQ(kWebConnectionTypeNone, notifier_.ConnectionType()); EXPECT_EQ(kWebConnectionTypeNone, notifier_.ConnectionType());
EXPECT_EQ(kNoneMaxBandwidthMbps, notifier_.MaxBandwidth()); EXPECT_EQ(kNoneMaxBandwidthMbps, notifier_.MaxBandwidth());
VerifyInitialMetricsWithWebHoldbackState(
kWebConnectionTypeNone, kNoneMaxBandwidthMbps,
WebEffectiveConnectionType::kTypeUnknown, kUnknownRtt,
kUnknownThroughputMbps, SaveData::kOff);
} }
TEST_F(NetworkStateNotifierTest, SetNetworkQualityInfoOverride) { TEST_F(NetworkStateNotifierTest, SetNetworkQualityInfoOverride) {
...@@ -626,6 +678,10 @@ TEST_F(NetworkStateNotifierTest, SetNetworkQualityInfoOverride) { ...@@ -626,6 +678,10 @@ TEST_F(NetworkStateNotifierTest, SetNetworkQualityInfoOverride) {
EXPECT_TRUE(notifier_.OnLine()); EXPECT_TRUE(notifier_.OnLine());
EXPECT_EQ(kWebConnectionTypeBluetooth, notifier_.ConnectionType()); EXPECT_EQ(kWebConnectionTypeBluetooth, notifier_.ConnectionType());
EXPECT_EQ(kBluetoothMaxBandwidthMbps, notifier_.MaxBandwidth()); EXPECT_EQ(kBluetoothMaxBandwidthMbps, notifier_.MaxBandwidth());
VerifyInitialMetricsWithWebHoldbackState(
kWebConnectionTypeBluetooth, kBluetoothMaxBandwidthMbps,
WebEffectiveConnectionType::kTypeUnknown, kUnknownRtt,
kUnknownThroughputMbps, SaveData::kOff);
notifier_.SetNetworkConnectionInfoOverride( notifier_.SetNetworkConnectionInfoOverride(
true, kWebConnectionTypeOther, WebEffectiveConnectionType::kType3G, true, kWebConnectionTypeOther, WebEffectiveConnectionType::kType3G,
...@@ -642,6 +698,10 @@ TEST_F(NetworkStateNotifierTest, SetNetworkQualityInfoOverride) { ...@@ -642,6 +698,10 @@ TEST_F(NetworkStateNotifierTest, SetNetworkQualityInfoOverride) {
EXPECT_EQ(WebEffectiveConnectionType::kType3G, notifier_.EffectiveType()); EXPECT_EQ(WebEffectiveConnectionType::kType3G, notifier_.EffectiveType());
EXPECT_EQ(kEthernetHttpRtt, notifier_.HttpRtt()); EXPECT_EQ(kEthernetHttpRtt, notifier_.HttpRtt());
EXPECT_EQ(kEthernetThroughputMbps, notifier_.DownlinkThroughputMbps()); EXPECT_EQ(kEthernetThroughputMbps, notifier_.DownlinkThroughputMbps());
VerifyInitialMetricsWithWebHoldbackState(
kWebConnectionTypeOther, kEthernetThroughputMbps.value(),
WebEffectiveConnectionType::kType3G, kEthernetHttpRtt,
kEthernetThroughputMbps, SaveData::kOff);
// When override is active, calls to SetConnection are temporary ignored. // When override is active, calls to SetConnection are temporary ignored.
notifier_.SetOnLine(false); notifier_.SetOnLine(false);
...@@ -966,4 +1026,29 @@ TEST_F(NetworkStateNotifierTest, SetNetworkConnectionInfoOverrideGenerateECTs) { ...@@ -966,4 +1026,29 @@ TEST_F(NetworkStateNotifierTest, SetNetworkConnectionInfoOverrideGenerateECTs) {
} }
} }
// Verify that network state notifier APIs return the correct value when the
// network quality web holdback experiment is enabled.
TEST_F(NetworkStateNotifierTest, SetNetInfoHoldback) {
VerifyInitialMetricsWithWebHoldbackState(
kWebConnectionTypeUnknown, kNoneMaxBandwidthMbps,
WebEffectiveConnectionType::kTypeUnknown, kUnknownRtt,
kUnknownThroughputMbps, SaveData::kOff);
EXPECT_FALSE(notifier_.GetWebHoldbackEffectiveType().has_value());
EXPECT_FALSE(notifier_.GetWebHoldbackHttpRtt().has_value());
EXPECT_FALSE(notifier_.GetWebHoldbackDownlinkThroughputMbps().has_value());
notifier_.SetNetworkQualityWebHoldback(WebEffectiveConnectionType::kType2G);
VerifyInitialMetricsWithWebHoldbackState(
kWebConnectionTypeUnknown, kNoneMaxBandwidthMbps,
WebEffectiveConnectionType::kType2G,
base::TimeDelta::FromMilliseconds(1800), 0.075, SaveData::kOff);
EXPECT_EQ(WebEffectiveConnectionType::kType2G,
notifier_.GetWebHoldbackEffectiveType().value());
EXPECT_EQ(base::TimeDelta::FromMilliseconds(1800),
notifier_.GetWebHoldbackHttpRtt().value());
EXPECT_EQ(0.075, notifier_.GetWebHoldbackDownlinkThroughputMbps().value());
}
} // namespace blink } // namespace blink
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment