diff options
author | tbansal <tbansal@chromium.org> | 2015-09-16 14:26:02 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-09-16 21:26:53 +0000 |
commit | b112feef767d087d6c40deb88c983d61c085d457 (patch) | |
tree | 19a4d5e0af0097f538636d6ef63efd87745c645c | |
parent | 8125ce3c695e6d8c02f3b51b16d49e17e7934bb4 (diff) | |
download | chromium_src-b112feef767d087d6c40deb88c983d61c085d457.zip chromium_src-b112feef767d087d6c40deb88c983d61c085d457.tar.gz chromium_src-b112feef767d087d6c40deb88c983d61c085d457.tar.bz2 |
Populate EEP estimate in NQE
Call EEP on every network change, and populate the estimates
into the NQE observation buffer.
BUG=472685
Committed: https://crrev.com/9ee5d296239e3bc21b5c70259242ce6c4cefc96b
Cr-Commit-Position: refs/heads/master@{#349032}
Review URL: https://codereview.chromium.org/1316863006
Cr-Commit-Position: refs/heads/master@{#349232}
-rw-r--r-- | chrome/browser/android/net/external_estimate_provider_android.cc | 34 | ||||
-rw-r--r-- | chrome/browser/android/net/external_estimate_provider_android.h | 21 | ||||
-rw-r--r-- | chrome/browser/android/net/external_estimate_provider_android_unittest.cc | 39 | ||||
-rw-r--r-- | net/base/external_estimate_provider.h | 4 | ||||
-rw-r--r-- | net/base/network_quality_estimator.cc | 71 | ||||
-rw-r--r-- | net/base/network_quality_estimator.h | 35 | ||||
-rw-r--r-- | net/base/network_quality_estimator_unittest.cc | 382 | ||||
-rw-r--r-- | tools/metrics/histograms/histograms.xml | 20 |
8 files changed, 517 insertions, 89 deletions
diff --git a/chrome/browser/android/net/external_estimate_provider_android.cc b/chrome/browser/android/net/external_estimate_provider_android.cc index 2d8c2db..4a02f3b 100644 --- a/chrome/browser/android/net/external_estimate_provider_android.cc +++ b/chrome/browser/android/net/external_estimate_provider_android.cc @@ -33,13 +33,6 @@ ExternalEstimateProviderAndroid::~ExternalEstimateProviderAndroid() { net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this); } -void ExternalEstimateProviderAndroid::RequestUpdate() const { - DCHECK(thread_checker_.CalledOnValidThread()); - JNIEnv* env = base::android::AttachCurrentThread(); - Java_ExternalEstimateProviderAndroid_requestUpdate( - env, j_external_estimate_provider_.obj()); -} - bool ExternalEstimateProviderAndroid::GetRTT(base::TimeDelta* rtt) const { DCHECK(thread_checker_.CalledOnValidThread()); JNIEnv* env = base::android::AttachCurrentThread(); @@ -96,6 +89,23 @@ bool ExternalEstimateProviderAndroid::GetTimeSinceLastUpdate( return true; } +void ExternalEstimateProviderAndroid::SetUpdatedEstimateDelegate( + net::ExternalEstimateProvider::UpdatedEstimateDelegate* delegate) { + delegate_ = delegate; +} + +void ExternalEstimateProviderAndroid::Update() const { + DCHECK(thread_checker_.CalledOnValidThread()); + JNIEnv* env = base::android::AttachCurrentThread(); + Java_ExternalEstimateProviderAndroid_requestUpdate( + env, j_external_estimate_provider_.obj()); +} + +void ExternalEstimateProviderAndroid::OnConnectionTypeChanged( + net::NetworkChangeNotifier::ConnectionType type) { + Update(); +} + void ExternalEstimateProviderAndroid:: NotifyExternalEstimateProviderAndroidUpdate(JNIEnv* env, jobject obj) { if (!task_runner_) @@ -113,19 +123,9 @@ void ExternalEstimateProviderAndroid::NotifyUpdatedEstimateAvailable() const { delegate_->OnUpdatedEstimateAvailable(); } -void ExternalEstimateProviderAndroid::OnConnectionTypeChanged( - net::NetworkChangeNotifier::ConnectionType type) { - RequestUpdate(); -} - bool RegisterExternalEstimateProviderAndroid(JNIEnv* env) { return RegisterNativesImpl(env); } -void ExternalEstimateProviderAndroid::SetUpdatedEstimateDelegate( - net::ExternalEstimateProvider::UpdatedEstimateDelegate* delegate) { - delegate_ = delegate; -} - } // namespace android } // namespace chrome diff --git a/chrome/browser/android/net/external_estimate_provider_android.h b/chrome/browser/android/net/external_estimate_provider_android.h index ad787e1..8fe6729 100644 --- a/chrome/browser/android/net/external_estimate_provider_android.h +++ b/chrome/browser/android/net/external_estimate_provider_android.h @@ -34,30 +34,23 @@ class ExternalEstimateProviderAndroid ~ExternalEstimateProviderAndroid() override; - // net::ExternalEstimateProvider implementation. + // net::ExternalEstimateProvider implementation: bool GetRTT(base::TimeDelta* rtt) const override; - - // net::ExternalEstimateProvider implementation. bool GetDownstreamThroughputKbps( int32_t* downstream_throughput_kbps) const override; - - // net::ExternalEstimateProvider implementation. bool GetUpstreamThroughputKbps( int32_t* upstream_throughput_kbps) const override; - - // net::ExternalEstimateProvider implementation. bool GetTimeSinceLastUpdate( base::TimeDelta* time_since_last_update) const override; + void SetUpdatedEstimateDelegate( + net::ExternalEstimateProvider::UpdatedEstimateDelegate* delegate) + override; + void Update() const override; // NetworkChangeNotifier::ConnectionTypeObserver implementation. void OnConnectionTypeChanged( net::NetworkChangeNotifier::ConnectionType type) override; - // net::ExternalEstimateProvider implementation. - void SetUpdatedEstimateDelegate( - net::ExternalEstimateProvider::UpdatedEstimateDelegate* delegate) - override; - // Called by Java when the external estimate provider has an updated value. // This may be called on a thread different from |task_runner_|. void NotifyExternalEstimateProviderAndroidUpdate(JNIEnv* env, jobject obj); @@ -68,10 +61,6 @@ class ExternalEstimateProviderAndroid void NotifyUpdatedEstimateAvailable() const; private: - // Places a requests to the provider to update the network quality. Returns - // true if the request was placed successfully. - void RequestUpdate() const; - // Value returned if valid value is unavailable. int32_t no_value_ = -1; diff --git a/chrome/browser/android/net/external_estimate_provider_android_unittest.cc b/chrome/browser/android/net/external_estimate_provider_android_unittest.cc index 26d9d10..1c80b09 100644 --- a/chrome/browser/android/net/external_estimate_provider_android_unittest.cc +++ b/chrome/browser/android/net/external_estimate_provider_android_unittest.cc @@ -6,6 +6,7 @@ #include <stdint.h> +#include "base/test/histogram_tester.h" #include "base/time/time.h" #include "net/base/network_quality_estimator.h" #include "testing/gtest/include/gtest/gtest.h" @@ -41,7 +42,10 @@ class TestNetworkQualityEstimator : public net::NetworkQualityEstimator { ~TestNetworkQualityEstimator() override {} - void OnUpdatedEstimateAvailable() override { notified_ = true; } + void OnUpdatedEstimateAvailable() override { + notified_ = true; + net::NetworkQualityEstimator::OnUpdatedEstimateAvailable(); + } bool IsNotified() const { return notified_; } @@ -56,11 +60,18 @@ class TestExternalEstimateProviderAndroid : chrome::android::ExternalEstimateProviderAndroid() {} ~TestExternalEstimateProviderAndroid() override {} using ExternalEstimateProviderAndroid::NotifyUpdatedEstimateAvailable; + + bool GetTimeSinceLastUpdate( + base::TimeDelta* time_since_last_update) const override { + *time_since_last_update = base::TimeDelta::FromMilliseconds(1); + return true; + } }; // Tests if the |ExternalEstimateProviderAndroid| notifies // |NetworkQualityEstimator|. TEST(ExternalEstimateProviderAndroidTest, DelegateTest) { + base::HistogramTester histogram_tester; scoped_ptr<TestExternalEstimateProviderAndroid> external_estimate_provider; external_estimate_provider.reset(new TestExternalEstimateProviderAndroid()); @@ -70,6 +81,32 @@ TEST(ExternalEstimateProviderAndroidTest, DelegateTest) { external_estimate_provider.Pass(), variation_params); ptr->NotifyUpdatedEstimateAvailable(); DCHECK(network_quality_estimator.IsNotified()); + + // EXTERNAL_ESTIMATE_PROVIDER_STATUS_NOT_AVAILABLE + histogram_tester.ExpectBucketCount("NQE.ExternalEstimateProviderStatus", 0, + 0); + + // EXTERNAL_ESTIMATE_PROVIDER_STATUS_AVAILABLE + histogram_tester.ExpectBucketCount("NQE.ExternalEstimateProviderStatus", 1, + 1); + + // EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERIED + // Updated once during NetworkQualityEstimator constructor and again, + // when |OnUpdatedEstimateAvailable| is called. + histogram_tester.ExpectBucketCount("NQE.ExternalEstimateProviderStatus", 2, + 2); + + // EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERY_SUCCESSFUL + // Updated once during NetworkQualityEstimator constructor and again, + // when |OnUpdatedEstimateAvailable| is called. + histogram_tester.ExpectBucketCount("NQE.ExternalEstimateProviderStatus", 3, + 2); + + // EXTERNAL_ESTIMATE_PROVIDER_STATUS_CALLBACK + histogram_tester.ExpectBucketCount("NQE.ExternalEstimateProviderStatus", 4, + 1); + + histogram_tester.ExpectTotalCount("NQE.ExternalEstimateProviderStatus", 6); } } // namespace diff --git a/net/base/external_estimate_provider.h b/net/base/external_estimate_provider.h index bc02988..c4480cf 100644 --- a/net/base/external_estimate_provider.h +++ b/net/base/external_estimate_provider.h @@ -59,6 +59,10 @@ class NET_EXPORT ExternalEstimateProvider { virtual void SetUpdatedEstimateDelegate( UpdatedEstimateDelegate* delegate) = 0; + // Requests an updated network quality estimate from the external estimate + // provider. + virtual void Update() const = 0; + private: DISALLOW_COPY_AND_ASSIGN(ExternalEstimateProvider); }; diff --git a/net/base/network_quality_estimator.cc b/net/base/network_quality_estimator.cc index 708a13c..d192bf0 100644 --- a/net/base/network_quality_estimator.cc +++ b/net/base/network_quality_estimator.cc @@ -178,7 +178,7 @@ NetworkQualityEstimator::NetworkQualityEstimator( downstream_throughput_kbps_observations_( GetWeightMultiplierPerSecond(variation_params)), rtt_msec_observations_(GetWeightMultiplierPerSecond(variation_params)), - external_estimates_provider_(external_estimates_provider.Pass()) { + external_estimate_provider_(external_estimates_provider.Pass()) { static_assert(kMinRequestDurationMicroseconds > 0, "Minimum request duration must be > 0"); static_assert(kDefaultHalfLifeSeconds > 0, @@ -192,8 +192,15 @@ NetworkQualityEstimator::NetworkQualityEstimator( ObtainOperatingParams(variation_params); NetworkChangeNotifier::AddConnectionTypeObserver(this); - if (external_estimates_provider_) - external_estimates_provider_->SetUpdatedEstimateDelegate(this); + if (external_estimate_provider_) { + RecordExternalEstimateProviderMetrics( + EXTERNAL_ESTIMATE_PROVIDER_STATUS_AVAILABLE); + external_estimate_provider_->SetUpdatedEstimateDelegate(this); + QueryExternalEstimateProvider(); + } else { + RecordExternalEstimateProviderMetrics( + EXTERNAL_ESTIMATE_PROVIDER_STATUS_NOT_AVAILABLE); + } current_network_id_ = GetCurrentNetworkID(); AddDefaultEstimates(); } @@ -210,6 +217,9 @@ void NetworkQualityEstimator::ObtainOperatingParams( for (size_t i = 0; i <= NetworkChangeNotifier::CONNECTION_LAST; ++i) { NetworkChangeNotifier::ConnectionType type = static_cast<NetworkChangeNotifier::ConnectionType>(i); + DCHECK_EQ(InvalidRTT(), default_observations_[i].rtt()); + DCHECK_EQ(kInvalidThroughput, + default_observations_[i].downstream_throughput_kbps()); int32_t variations_value = kMinimumRTTVariationParameterMsec - 1; // Name of the parameter that holds the RTT value for this connection type. std::string rtt_parameter_name = @@ -419,6 +429,12 @@ bool NetworkQualityEstimator::RequestProvidesUsefulObservations( request.creation_time() >= last_connection_change_; } +void NetworkQualityEstimator::RecordExternalEstimateProviderMetrics( + NQEExternalEstimateProviderStatus status) const { + UMA_HISTOGRAM_ENUMERATION("NQE.ExternalEstimateProviderStatus", status, + EXTERNAL_ESTIMATE_PROVIDER_STATUS_BOUNDARY); +} + void NetworkQualityEstimator::OnConnectionTypeChanged( NetworkChangeNotifier::ConnectionType type) { DCHECK(thread_checker_.CalledOnValidThread()); @@ -538,6 +554,8 @@ void NetworkQualityEstimator::OnConnectionTypeChanged( rtt_msec_observations_.Clear(); current_network_id_ = GetCurrentNetworkID(); + QueryExternalEstimateProvider(); + // Read any cached estimates for the new network. If cached estimates are // unavailable, add the default estimates. if (!ReadCachedNetworkQualityEstimate()) @@ -812,8 +830,51 @@ bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() { void NetworkQualityEstimator::OnUpdatedEstimateAvailable() { DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK(external_estimates_provider_); - // TODO(tbansal): Query provider for the recent value. + DCHECK(external_estimate_provider_); + + RecordExternalEstimateProviderMetrics( + EXTERNAL_ESTIMATE_PROVIDER_STATUS_CALLBACK); + QueryExternalEstimateProvider(); +} + +void NetworkQualityEstimator::QueryExternalEstimateProvider() { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (!external_estimate_provider_) + return; + RecordExternalEstimateProviderMetrics( + EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERIED); + + base::TimeDelta time_since_last_update; + + // Request a new estimate if estimate is not available, or if the available + // estimate is not fresh. + if (!external_estimate_provider_->GetTimeSinceLastUpdate( + &time_since_last_update) || + time_since_last_update > + base::TimeDelta::FromMilliseconds( + kExternalEstimateProviderFreshnessDurationMsec)) { + // Request the external estimate provider for updated estimates. When the + // updates estimates are available, OnUpdatedEstimateAvailable() will be + // called. + external_estimate_provider_->Update(); + return; + } + + RecordExternalEstimateProviderMetrics( + EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERY_SUCCESSFUL); + base::TimeDelta rtt; + if (external_estimate_provider_->GetRTT(&rtt)) { + rtt_msec_observations_.AddObservation( + Observation(rtt.InMilliseconds(), base::TimeTicks::Now())); + } + + int32_t downstream_throughput_kbps; + if (external_estimate_provider_->GetDownstreamThroughputKbps( + &downstream_throughput_kbps)) { + downstream_throughput_kbps_observations_.AddObservation( + Observation(downstream_throughput_kbps, base::TimeTicks::Now())); + } } void NetworkQualityEstimator::CacheNetworkQualityEstimate() { diff --git a/net/base/network_quality_estimator.h b/net/base/network_quality_estimator.h index aba0313..f951bd4 100644 --- a/net/base/network_quality_estimator.h +++ b/net/base/network_quality_estimator.h @@ -149,6 +149,9 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator void OnConnectionTypeChanged( NetworkChangeNotifier::ConnectionType type) override; + // ExternalEstimateProvider::UpdatedEstimateObserver implementation. + void OnUpdatedEstimateAvailable() override; + private: FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, StoreObservations); FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestKbpsRTTUpdates); @@ -165,6 +168,10 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestLRUCacheMaximumSize); FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestGetMedianRTTSince); + FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, + TestExternalEstimateProvider); + FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, + TestExternalEstimateProviderMergeEstimates); // NetworkQuality is used to cache the quality of a network connection. class NET_EXPORT_PRIVATE NetworkQuality { @@ -352,12 +359,18 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator // Maximum number of observations that can be held in the ObservationBuffer. static const size_t kMaximumObservationsBufferSize = 300; + // Time duration (in milliseconds) after which the estimate provided by + // external estimate provider is considered stale. + static const int kExternalEstimateProviderFreshnessDurationMsec = + 5 * 60 * 1000; + // Returns the RTT value to be used when the valid RTT is unavailable. Readers // should discard RTT if it is set to the value returned by |InvalidRTT()|. static const base::TimeDelta InvalidRTT(); - // ExternalEstimateProvider::UpdatedEstimateObserver implementation: - void OnUpdatedEstimateAvailable() override; + // Queries the external estimate provider for the latest network quality + // estimates, and adds those estimates to the current observation buffer. + void QueryExternalEstimateProvider(); // Obtains operating parameters from the field trial parameters. void ObtainOperatingParams( @@ -396,6 +409,22 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator // observations. bool RequestProvidesUsefulObservations(const URLRequest& request) const; + // Values of external estimate provider status. This enum must remain + // synchronized with the enum of the same name in + // metrics/histograms/histograms.xml. + enum NQEExternalEstimateProviderStatus { + EXTERNAL_ESTIMATE_PROVIDER_STATUS_NOT_AVAILABLE, + EXTERNAL_ESTIMATE_PROVIDER_STATUS_AVAILABLE, + EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERIED, + EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERY_SUCCESSFUL, + EXTERNAL_ESTIMATE_PROVIDER_STATUS_CALLBACK, + EXTERNAL_ESTIMATE_PROVIDER_STATUS_BOUNDARY + }; + + // Records the metrics related to external estimate provider. + void RecordExternalEstimateProviderMetrics( + NQEExternalEstimateProviderStatus status) const; + // Determines if the requests to local host can be used in estimating the // network quality. Set to true only for tests. const bool allow_localhost_requests_; @@ -439,7 +468,7 @@ class NET_EXPORT_PRIVATE NetworkQualityEstimator // ExternalEstimateProvider that provides network quality using operating // system APIs. May be NULL. - const scoped_ptr<ExternalEstimateProvider> external_estimates_provider_; + const scoped_ptr<ExternalEstimateProvider> external_estimate_provider_; base::ThreadChecker thread_checker_; diff --git a/net/base/network_quality_estimator_unittest.cc b/net/base/network_quality_estimator_unittest.cc index b1ffdeb..38a22eb 100644 --- a/net/base/network_quality_estimator_unittest.cc +++ b/net/base/network_quality_estimator_unittest.cc @@ -10,6 +10,7 @@ #include <map> #include "base/basictypes.h" +#include "base/files/file_path.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/metrics/histogram_samples.h" @@ -21,22 +22,47 @@ #include "net/base/external_estimate_provider.h" #include "net/base/load_flags.h" #include "net/base/network_change_notifier.h" -#include "net/test/embedded_test_server/embedded_test_server.h" +#include "net/http/http_status_code.h" +#include "net/test/spawned_test_server/spawned_test_server.h" #include "net/url_request/url_request_test_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" namespace { +#if !defined(OS_IOS) +// SpawnedTestServer is not supported on iOS. +// Less verbose way of running a simple testserver for the tests below. +class LocalHttpTestServer : public net::SpawnedTestServer { + public: + LocalHttpTestServer() + : net::SpawnedTestServer(net::SpawnedTestServer::TYPE_HTTP, + net::SpawnedTestServer::kLocalhost, + base::FilePath()) {} +}; +#endif // !defined(OS_IOS) + // Helps in setting the current network type and id. class TestNetworkQualityEstimator : public net::NetworkQualityEstimator { public: TestNetworkQualityEstimator( - const std::map<std::string, std::string>& variation_params) - : NetworkQualityEstimator(scoped_ptr<net::ExternalEstimateProvider>(), + const std::map<std::string, std::string>& variation_params, + scoped_ptr<net::ExternalEstimateProvider> external_estimate_provider) + : NetworkQualityEstimator(external_estimate_provider.Pass(), variation_params, true, - true) {} + true) { +#if !defined(OS_IOS) + // Set up test server. + DCHECK(test_server_.Start()); +#endif // !defined(OS_IOS) + } + + explicit TestNetworkQualityEstimator( + const std::map<std::string, std::string>& variation_params) + : TestNetworkQualityEstimator( + variation_params, + scoped_ptr<net::ExternalEstimateProvider>()) {} ~TestNetworkQualityEstimator() override {} @@ -49,6 +75,11 @@ class TestNetworkQualityEstimator : public net::NetworkQualityEstimator { OnConnectionTypeChanged(type); } +#if !defined(OS_IOS) + // Returns a GURL hosted at embedded test server. + const GURL GetEchoURL() const { return test_server_.GetURL("/echo.html"); } +#endif // !defined(OS_IOS) + using NetworkQualityEstimator::ReadCachedNetworkQualityEstimate; using NetworkQualityEstimator::OnConnectionTypeChanged; @@ -62,18 +93,22 @@ class TestNetworkQualityEstimator : public net::NetworkQualityEstimator { net::NetworkChangeNotifier::ConnectionType current_network_type_; std::string current_network_id_; + +#if !defined(OS_IOS) + // Test server used for testing. + LocalHttpTestServer test_server_; +#endif // !defined(OS_IOS) + + DISALLOW_COPY_AND_ASSIGN(TestNetworkQualityEstimator); }; } // namespace namespace net { +#if !defined(OS_IOS) +// SpawnedTestServer is not supported on iOS. TEST(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) { - net::test_server::EmbeddedTestServer embedded_test_server; - embedded_test_server.ServeFilesFromDirectory( - base::FilePath(FILE_PATH_LITERAL("net/data/url_request_unittest"))); - ASSERT_TRUE(embedded_test_server.InitializeAndWaitUntilReady()); - base::HistogramTester histogram_tester; // Enable requests to local host to be used for network quality estimation. std::map<std::string, std::string> variation_params; @@ -86,19 +121,17 @@ TEST(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) { base::TimeTicks(), 100)); TestDelegate test_delegate; - TestURLRequestContext context(false); + TestURLRequestContext context(true); + context.set_network_quality_estimator(&estimator); + context.Init(); - scoped_ptr<URLRequest> request( - context.CreateRequest(embedded_test_server.GetURL("/echo.html"), - DEFAULT_PRIORITY, &test_delegate)); + scoped_ptr<URLRequest> request(context.CreateRequest( + estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate)); request->SetLoadFlags(request->load_flags() | LOAD_MAIN_FRAME); request->Start(); - base::RunLoop().Run(); // Both RTT and downstream throughput should be updated. - estimator.NotifyHeadersReceived(*request); - estimator.NotifyRequestCompleted(*request); EXPECT_NE(NetworkQualityEstimator::InvalidRTT(), estimator.GetRTTEstimateInternal(base::TimeTicks(), 100)); EXPECT_NE(NetworkQualityEstimator::kInvalidThroughput, @@ -123,8 +156,12 @@ TEST(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) { histogram_tester.ExpectTotalCount("NQE.RatioEstimatedToActualRTT.Unknown", 0); - estimator.NotifyHeadersReceived(*request); - estimator.NotifyRequestCompleted(*request); + scoped_ptr<URLRequest> request2(context.CreateRequest( + estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate)); + request2->SetLoadFlags(request2->load_flags() | LOAD_MAIN_FRAME); + request2->Start(); + base::RunLoop().Run(); + histogram_tester.ExpectTotalCount("NQE.RTTObservations.Unknown", 1); estimator.SimulateNetworkChangeTo( NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1"); @@ -166,26 +203,20 @@ TEST(NetworkQualityEstimatorTest, TestKbpsRTTUpdates) { } TEST(NetworkQualityEstimatorTest, StoreObservations) { - net::test_server::EmbeddedTestServer embedded_test_server; - embedded_test_server.ServeFilesFromDirectory( - base::FilePath(FILE_PATH_LITERAL("net/data/url_request_unittest"))); - ASSERT_TRUE(embedded_test_server.InitializeAndWaitUntilReady()); - std::map<std::string, std::string> variation_params; TestNetworkQualityEstimator estimator(variation_params); + TestDelegate test_delegate; - TestURLRequestContext context(false); + TestURLRequestContext context(true); + context.set_network_quality_estimator(&estimator); + context.Init(); // Push 10 more observations than the maximum buffer size. for (size_t i = 0; i < estimator.kMaximumObservationsBufferSize + 10U; ++i) { - scoped_ptr<URLRequest> request( - context.CreateRequest(embedded_test_server.GetURL("/echo.html"), - DEFAULT_PRIORITY, &test_delegate)); + scoped_ptr<URLRequest> request(context.CreateRequest( + estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate)); request->Start(); base::RunLoop().Run(); - - estimator.NotifyHeadersReceived(*request); - estimator.NotifyRequestCompleted(*request); } EXPECT_EQ(static_cast<size_t>( @@ -200,11 +231,8 @@ TEST(NetworkQualityEstimatorTest, StoreObservations) { NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-2"); EXPECT_EQ(0U, estimator.downstream_throughput_kbps_observations_.Size()); EXPECT_EQ(0U, estimator.rtt_msec_observations_.Size()); - - scoped_ptr<URLRequest> request( - context.CreateRequest(embedded_test_server.GetURL("/echo.html"), - DEFAULT_PRIORITY, &test_delegate)); } +#endif // !defined(OS_IOS) // Verifies that the percentiles are correctly computed. All observations have // the same timestamp. Kbps percentiles must be in decreasing order. RTT @@ -315,12 +343,9 @@ TEST(NetworkQualityEstimatorTest, PercentileDifferentTimestamps) { // This test notifies NetworkQualityEstimator of received data. Next, // throughput and RTT percentiles are checked for correctness by doing simple // verifications. +#if !defined(OS_IOS) +// SpawnedTestServer is not supported on iOS. TEST(NetworkQualityEstimatorTest, ComputedPercentiles) { - net::test_server::EmbeddedTestServer embedded_test_server; - embedded_test_server.ServeFilesFromDirectory( - base::FilePath(FILE_PATH_LITERAL("net/data/url_request_unittest"))); - ASSERT_TRUE(embedded_test_server.InitializeAndWaitUntilReady()); - std::map<std::string, std::string> variation_params; TestNetworkQualityEstimator estimator(variation_params); @@ -331,19 +356,16 @@ TEST(NetworkQualityEstimatorTest, ComputedPercentiles) { base::TimeTicks(), 100)); TestDelegate test_delegate; - TestURLRequestContext context(false); + TestURLRequestContext context(true); + context.set_network_quality_estimator(&estimator); + context.Init(); // Number of observations are more than the maximum buffer size. for (size_t i = 0; i < estimator.kMaximumObservationsBufferSize + 100U; ++i) { - scoped_ptr<URLRequest> request( - context.CreateRequest(embedded_test_server.GetURL("/echo.html"), - DEFAULT_PRIORITY, &test_delegate)); + scoped_ptr<URLRequest> request(context.CreateRequest( + estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate)); request->Start(); base::RunLoop().Run(); - - // Use different number of bytes to create variation. - estimator.NotifyHeadersReceived(*request); - estimator.NotifyRequestCompleted(*request); } // Verify the percentiles through simple tests. @@ -367,6 +389,7 @@ TEST(NetworkQualityEstimatorTest, ComputedPercentiles) { } } } +#endif // !defined(OS_IOS) TEST(NetworkQualityEstimatorTest, ObtainOperatingParams) { std::map<std::string, std::string> variation_params; @@ -654,4 +677,269 @@ TEST(NetworkQualityEstimatorTest, TestGetMedianRTTSince) { EXPECT_EQ(100, downstream_throughput_kbps); } +// An external estimate provider that does not have a valid RTT or throughput +// estimate. +class InvalidExternalEstimateProvider : public ExternalEstimateProvider { + public: + InvalidExternalEstimateProvider() : get_rtt_count_(0) {} + ~InvalidExternalEstimateProvider() override {} + + // ExternalEstimateProvider implementation: + bool GetRTT(base::TimeDelta* rtt) const override { + DCHECK(rtt); + get_rtt_count_++; + return false; + } + + // ExternalEstimateProvider implementation: + bool GetDownstreamThroughputKbps( + int32_t* downstream_throughput_kbps) const override { + DCHECK(downstream_throughput_kbps); + return false; + } + + // ExternalEstimateProvider implementation: + bool GetUpstreamThroughputKbps( + int32_t* upstream_throughput_kbps) const override { + // NetworkQualityEstimator does not support upstream throughput. + ADD_FAILURE(); + return false; + } + + // ExternalEstimateProvider implementation: + bool GetTimeSinceLastUpdate( + base::TimeDelta* time_since_last_update) const override { + *time_since_last_update = base::TimeDelta::FromMilliseconds(1); + return true; + } + + // ExternalEstimateProvider implementation: + void SetUpdatedEstimateDelegate(UpdatedEstimateDelegate* delegate) override {} + + // ExternalEstimateProvider implementation: + void Update() const override {} + + size_t get_rtt_count() const { return get_rtt_count_; } + + private: + // Keeps track of number of times different functions were called. + mutable size_t get_rtt_count_; + + DISALLOW_COPY_AND_ASSIGN(InvalidExternalEstimateProvider); +}; + +// Tests if the RTT value from external estimate provider is discarded if the +// external estimate provider is invalid. +TEST(NetworkQualityEstimatorTest, InvalidExternalEstimateProvider) { + InvalidExternalEstimateProvider* invalid_external_estimate_provider = + new InvalidExternalEstimateProvider(); + scoped_ptr<ExternalEstimateProvider> external_estimate_provider( + invalid_external_estimate_provider); + + TestNetworkQualityEstimator estimator(std::map<std::string, std::string>(), + external_estimate_provider.Pass()); + + base::TimeDelta rtt; + int32_t kbps; + EXPECT_EQ(1U, invalid_external_estimate_provider->get_rtt_count()); + EXPECT_FALSE(estimator.GetRTTEstimate(&rtt)); + EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); +} + +class TestExternalEstimateProvider : public ExternalEstimateProvider { + public: + TestExternalEstimateProvider(base::TimeDelta rtt, + int32_t downstream_throughput_kbps) + : rtt_(rtt), + downstream_throughput_kbps_(downstream_throughput_kbps), + time_since_last_update_(base::TimeDelta::FromSeconds(1)), + get_time_since_last_update_count_(0), + get_rtt_count_(0), + get_downstream_throughput_kbps_count_(0), + update_count_(0) {} + ~TestExternalEstimateProvider() override {} + + // ExternalEstimateProvider implementation: + bool GetRTT(base::TimeDelta* rtt) const override { + *rtt = rtt_; + get_rtt_count_++; + return true; + } + + // ExternalEstimateProvider implementation: + bool GetDownstreamThroughputKbps( + int32_t* downstream_throughput_kbps) const override { + *downstream_throughput_kbps = downstream_throughput_kbps_; + get_downstream_throughput_kbps_count_++; + return true; + } + + // ExternalEstimateProvider implementation: + bool GetUpstreamThroughputKbps( + int32_t* upstream_throughput_kbps) const override { + // NetworkQualityEstimator does not support upstream throughput. + ADD_FAILURE(); + return false; + } + + // ExternalEstimateProvider implementation: + bool GetTimeSinceLastUpdate( + base::TimeDelta* time_since_last_update) const override { + *time_since_last_update = time_since_last_update_; + get_time_since_last_update_count_++; + return true; + } + + // ExternalEstimateProvider implementation: + void SetUpdatedEstimateDelegate(UpdatedEstimateDelegate* delegate) override {} + + // ExternalEstimateProvider implementation: + void Update() const override { update_count_++; } + + void set_time_since_last_update(base::TimeDelta time_since_last_update) { + time_since_last_update_ = time_since_last_update; + } + + size_t get_time_since_last_update_count() const { + return get_time_since_last_update_count_; + } + size_t get_rtt_count() const { return get_rtt_count_; } + size_t get_downstream_throughput_kbps_count() const { + return get_downstream_throughput_kbps_count_; + } + size_t update_count() const { return update_count_; } + + private: + // RTT and downstream throughput estimates. + const base::TimeDelta rtt_; + const int32_t downstream_throughput_kbps_; + + base::TimeDelta time_since_last_update_; + + // Keeps track of number of times different functions were called. + mutable size_t get_time_since_last_update_count_; + mutable size_t get_rtt_count_; + mutable size_t get_downstream_throughput_kbps_count_; + mutable size_t update_count_; + + DISALLOW_COPY_AND_ASSIGN(TestExternalEstimateProvider); +}; + +// Tests if the external estimate provider is called in the constructor and +// on network change notification. +TEST(NetworkQualityEstimatorTest, TestExternalEstimateProvider) { + TestExternalEstimateProvider* test_external_estimate_provider = + new TestExternalEstimateProvider(base::TimeDelta::FromMilliseconds(1), + 100); + scoped_ptr<ExternalEstimateProvider> external_estimate_provider( + test_external_estimate_provider); + std::map<std::string, std::string> variation_params; + TestNetworkQualityEstimator estimator(variation_params, + external_estimate_provider.Pass()); + + base::TimeDelta rtt; + int32_t kbps; + EXPECT_TRUE(estimator.GetRTTEstimate(&rtt)); + EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); + + EXPECT_EQ( + 1U, test_external_estimate_provider->get_time_since_last_update_count()); + EXPECT_EQ(1U, test_external_estimate_provider->get_rtt_count()); + EXPECT_EQ( + 1U, + test_external_estimate_provider->get_downstream_throughput_kbps_count()); + + // Change network type to WiFi. Number of queries to External estimate + // provider must increment. + estimator.SimulateNetworkChangeTo( + NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1"); + EXPECT_TRUE(estimator.GetRTTEstimate(&rtt)); + EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); + EXPECT_EQ( + 2U, test_external_estimate_provider->get_time_since_last_update_count()); + EXPECT_EQ(2U, test_external_estimate_provider->get_rtt_count()); + EXPECT_EQ( + 2U, + test_external_estimate_provider->get_downstream_throughput_kbps_count()); + + // Change network type to 2G. Number of queries to External estimate provider + // must increment. + estimator.SimulateNetworkChangeTo( + NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-1"); + EXPECT_EQ( + 3U, test_external_estimate_provider->get_time_since_last_update_count()); + EXPECT_EQ(3U, test_external_estimate_provider->get_rtt_count()); + EXPECT_EQ( + 3U, + test_external_estimate_provider->get_downstream_throughput_kbps_count()); + + // Set the external estimate as old. Network Quality estimator should request + // an update on connection type change. + EXPECT_EQ(0U, test_external_estimate_provider->update_count()); + test_external_estimate_provider->set_time_since_last_update( + base::TimeDelta::Max()); + + estimator.SimulateNetworkChangeTo( + NetworkChangeNotifier::ConnectionType::CONNECTION_2G, "test-2"); + EXPECT_EQ( + 4U, test_external_estimate_provider->get_time_since_last_update_count()); + EXPECT_EQ(3U, test_external_estimate_provider->get_rtt_count()); + EXPECT_EQ( + 3U, + test_external_estimate_provider->get_downstream_throughput_kbps_count()); + EXPECT_EQ(1U, test_external_estimate_provider->update_count()); + + // Estimates are unavailable because external estimate provider never + // notifies network quality estimator of the updated estimates. + EXPECT_FALSE(estimator.GetRTTEstimate(&rtt)); + EXPECT_FALSE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); +} + +// Tests if the estimate from the external estimate provider is merged with the +// observations collected from the HTTP requests. +#if !defined(OS_IOS) +// SpawnedTestServer is not supported on iOS. +TEST(NetworkQualityEstimatorTest, TestExternalEstimateProviderMergeEstimates) { + const base::TimeDelta external_estimate_provider_rtt = + base::TimeDelta::FromMilliseconds(1); + const int32_t external_estimate_provider_downstream_throughput = 100; + TestExternalEstimateProvider* test_external_estimate_provider = + new TestExternalEstimateProvider( + external_estimate_provider_rtt, + external_estimate_provider_downstream_throughput); + scoped_ptr<ExternalEstimateProvider> external_estimate_provider( + test_external_estimate_provider); + + std::map<std::string, std::string> variation_params; + TestNetworkQualityEstimator estimator(variation_params, + external_estimate_provider.Pass()); + + base::TimeDelta rtt; + // Estimate provided by network quality estimator should match the estimate + // provided by external estimate provider. + EXPECT_TRUE(estimator.GetRTTEstimate(&rtt)); + EXPECT_EQ(external_estimate_provider_rtt, rtt); + + int32_t kbps; + EXPECT_TRUE(estimator.GetDownlinkThroughputKbpsEstimate(&kbps)); + EXPECT_EQ(external_estimate_provider_downstream_throughput, kbps); + + EXPECT_EQ(1U, estimator.rtt_msec_observations_.Size()); + EXPECT_EQ(1U, estimator.downstream_throughput_kbps_observations_.Size()); + + TestDelegate test_delegate; + TestURLRequestContext context(true); + context.set_network_quality_estimator(&estimator); + context.Init(); + + scoped_ptr<URLRequest> request(context.CreateRequest( + estimator.GetEchoURL(), DEFAULT_PRIORITY, &test_delegate)); + request->Start(); + base::RunLoop().Run(); + + EXPECT_EQ(2U, estimator.rtt_msec_observations_.Size()); + EXPECT_EQ(2U, estimator.downstream_throughput_kbps_observations_.Size()); +} +#endif // !defined(OS_IOS) + } // namespace net diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 677ff2e..49e0cc6 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -28577,6 +28577,18 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries. </summary> </histogram> +<histogram name="NQE.ExternalEstimateProviderStatus" + enum="NQEExternalEstimateProviderStatus"> + <owner>bengr@chromium.org</owner> + <owner>tbansal@chromium.org</owner> + <summary> + Records the interaction (availability and query count) of Network Quality + Estimator with external estimates provider. Logged on network change events, + everytime external estimate provider is queried for an updated estimate, and + when it proactively notifies that an updated estimate is available. + </summary> +</histogram> + <histogram name="NQE.FastestRTT" units="milliseconds"> <owner>bengr@chromium.org</owner> <owner>tbansal@chromium.org</owner> @@ -66899,6 +66911,14 @@ To add a new entry, add it with any value and run test to compute valid value. <int value="2" label="Enabled">NPAPI is enabled</int> </enum> +<enum name="NQEExternalEstimateProviderStatus" type="int"> + <int value="0" label="External estimate provider was not available"/> + <int value="1" label="External estimate provider was available"/> + <int value="2" label="External estimate provider was queried"/> + <int value="3" label="Query to external estimate provider was successful"/> + <int value="4" label="Callback received from external estimate provider"/> +</enum> + <enum name="NtpFollowAction" type="int"> <int value="0" label="PAGE_TRANSITION_LINK"/> <int value="1" label="PAGE_TRANSITION_TYPED"/> |