blob: 38ed6a08ba06bbd6179a9828b8f7d458f5a6055b [file] [log] [blame]
tbansal80a52162016-05-20 17:55:041// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/nqe/throughput_analyzer.h"
6
7#include <stdint.h>
8
tbansalff83205e2017-05-23 00:09:459#include <map>
tbansal80a52162016-05-20 17:55:0410#include <memory>
tbansalff83205e2017-05-23 00:09:4511#include <string>
tbansal82edab42017-06-19 05:55:2512#include <utility>
13#include <vector>
tbansal80a52162016-05-20 17:55:0414
15#include "base/bind.h"
danakjdb9ae7942020-11-11 16:01:3516#include "base/callback_helpers.h"
Brett Wilsonc6a0c822017-09-12 00:04:2917#include "base/containers/circular_deque.h"
Weza3ec3fe2020-02-17 12:52:1618#include "base/location.h"
tbansal80a52162016-05-20 17:55:0419#include "base/run_loop.h"
tbansalff83205e2017-05-23 00:09:4520#include "base/strings/string_number_conversions.h"
Patrick Monette643cdf62021-10-15 19:13:4221#include "base/task/single_thread_task_runner.h"
Devlin Cronine4bcb40e2018-06-05 18:02:4722#include "base/test/metrics/histogram_tester.h"
Matt Menkea7e697122019-11-06 00:47:5723#include "base/test/scoped_feature_list.h"
Tarun Bansal00943112017-10-10 22:49:1424#include "base/test/simple_test_tick_clock.h"
Wez92e1e1332019-09-19 21:57:5625#include "base/test/test_timeouts.h"
Tarun Bansal00943112017-10-10 22:49:1426#include "base/threading/platform_thread.h"
tbansal80a52162016-05-20 17:55:0427#include "base/threading/thread_task_runner_handle.h"
Tarun Bansal00943112017-10-10 22:49:1428#include "base/time/default_tick_clock.h"
Gabriel Charetted87f10f2022-03-31 00:44:2229#include "base/time/time.h"
Justin Cohen8bfb6b72020-07-27 18:22:2530#include "build/build_config.h"
Matt Menkea7e697122019-11-06 00:47:5731#include "net/base/features.h"
Matt Menke3ab9c7b2020-04-01 22:39:5732#include "net/base/isolation_info.h"
Matt Menke4807a9a2020-11-21 00:14:4133#include "net/base/schemeful_site.h"
tbansal82edab42017-06-19 05:55:2534#include "net/dns/mock_host_resolver.h"
Tarun Bansaled2b20b642018-10-15 19:51:3235#include "net/nqe/network_quality_estimator.h"
tbansalff83205e2017-05-23 00:09:4536#include "net/nqe/network_quality_estimator_params.h"
Tarun Bansaled2b20b642018-10-15 19:51:3237#include "net/nqe/network_quality_estimator_test_util.h"
tbansal82edab42017-06-19 05:55:2538#include "net/nqe/network_quality_estimator_util.h"
Gabriel Charettec7108742019-08-23 03:31:4039#include "net/test/test_with_task_environment.h"
rhalavati9ebaba7e2017-04-27 06:16:2940#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
tbansal80a52162016-05-20 17:55:0441#include "net/url_request/url_request.h"
Yutaka Hirano36ab60c72022-03-17 08:30:3742#include "net/url_request/url_request_context.h"
43#include "net/url_request/url_request_context_builder.h"
tbansal80a52162016-05-20 17:55:0444#include "net/url_request/url_request_test_util.h"
45#include "testing/gtest/include/gtest/gtest.h"
Matt Menkea7e697122019-11-06 00:47:5746#include "url/gurl.h"
tbansal80a52162016-05-20 17:55:0447
Tsuyoshi Horo4f516be2022-06-14 11:53:1348namespace net::nqe {
tbansal80a52162016-05-20 17:55:0449
50namespace {
51
Yutaka Hirano36ab60c72022-03-17 08:30:3752// Creates a mock resolver mapping example.com to a public IP address.
53std::unique_ptr<HostResolver> CreateMockHostResolver() {
54 auto host_resolver = std::make_unique<MockCachingHostResolver>(
55 /*cache_invalidation_num=*/0,
56 /*default_result=*/ERR_NAME_NOT_RESOLVED);
57
58 // local.com resolves to a private IP address.
59 host_resolver->rules()->AddRule("local.com", "127.0.0.1");
60 host_resolver->LoadIntoCache(HostPortPair("local.com", 80),
61 NetworkIsolationKey(), absl::nullopt);
62 // Hosts not listed here (e.g., "example.com") are treated as external. See
63 // ThroughputAnalyzerTest.PrivateHost below.
64
65 return host_resolver;
66}
67
tbansal80a52162016-05-20 17:55:0468class TestThroughputAnalyzer : public internal::ThroughputAnalyzer {
69 public:
Tarun Bansaled2b20b642018-10-15 19:51:3270 TestThroughputAnalyzer(NetworkQualityEstimator* network_quality_estimator,
Tarun Bansal00943112017-10-10 22:49:1471 NetworkQualityEstimatorParams* params,
Greg Thompsonaa48ce8d2018-04-03 06:11:4372 const base::TickClock* tick_clock)
tbansal80a52162016-05-20 17:55:0473 : internal::ThroughputAnalyzer(
Tarun Bansaled2b20b642018-10-15 19:51:3274 network_quality_estimator,
tbansalff83205e2017-05-23 00:09:4575 params,
tbansal80a52162016-05-20 17:55:0476 base::ThreadTaskRunnerHandle::Get(),
Anna Malova2592bd4a2020-03-03 15:52:1677 base::BindRepeating(
tbansal80a52162016-05-20 17:55:0478 &TestThroughputAnalyzer::OnNewThroughputObservationAvailable,
79 base::Unretained(this)),
Tarun Bansal00943112017-10-10 22:49:1480 tick_clock,
Tsuyoshi Horo2fa6b8de2022-06-09 01:40:2081 NetLogWithSource::Make(NetLogSourceType::NONE)) {}
tbansal80a52162016-05-20 17:55:0482
Peter Boström293b1342021-09-22 17:31:4383 TestThroughputAnalyzer(const TestThroughputAnalyzer&) = delete;
84 TestThroughputAnalyzer& operator=(const TestThroughputAnalyzer&) = delete;
85
Chris Watkinsf3c65a62017-12-01 02:06:4186 ~TestThroughputAnalyzer() override = default;
tbansal80a52162016-05-20 17:55:0487
88 int32_t throughput_observations_received() const {
89 return throughput_observations_received_;
90 }
91
92 void OnNewThroughputObservationAvailable(int32_t downstream_kbps) {
93 throughput_observations_received_++;
94 }
95
96 int64_t GetBitsReceived() const override { return bits_received_; }
97
98 void IncrementBitsReceived(int64_t additional_bits_received) {
99 bits_received_ += additional_bits_received;
100 }
101
Jianfeng Wang25d28452019-07-17 00:35:21102 using internal::ThroughputAnalyzer::CountActiveInFlightRequests;
Jianfeng Wange829c4982019-07-03 21:17:09103 using internal::ThroughputAnalyzer::
104 disable_throughput_measurements_for_testing;
Tarun Bansal00943112017-10-10 22:49:14105 using internal::ThroughputAnalyzer::EraseHangingRequests;
Tarun Bansal8914dbba2017-12-12 21:03:59106 using internal::ThroughputAnalyzer::IsHangingWindow;
tbansal80a52162016-05-20 17:55:04107
108 private:
Tsuyoshi Horo2fa6b8de2022-06-09 01:40:20109 int throughput_observations_received_ = 0;
tbansal80a52162016-05-20 17:55:04110
Tsuyoshi Horo2fa6b8de2022-06-09 01:40:20111 int64_t bits_received_ = 0;
tbansal80a52162016-05-20 17:55:04112};
113
Gabriel Charette694c3c332019-08-19 14:53:05114using ThroughputAnalyzerTest = TestWithTaskEnvironment;
Bence Béky98447b12018-05-08 03:14:01115
Yutaka Hirano36ab60c72022-03-17 08:30:37116TEST_F(ThroughputAnalyzerTest, PrivateHost) {
117 auto host_resolver = CreateMockHostResolver();
118 EXPECT_FALSE(nqe::internal::IsPrivateHostForTesting(
119 host_resolver.get(), HostPortPair("example.com", 80),
120 NetworkIsolationKey()));
121 EXPECT_TRUE(nqe::internal::IsPrivateHostForTesting(
122 host_resolver.get(), HostPortPair("local.com", 80),
123 NetworkIsolationKey()));
124}
125
Xiaohan Wang2a6845b2022-01-08 04:40:57126#if BUILDFLAG(IS_IOS) || BUILDFLAG(IS_ANDROID)
Justin Cohen8bfb6b72020-07-27 18:22:25127// Flaky on iOS: crbug.com/672917.
Egor Pasko0198f252021-09-09 15:09:17128// Flaky on Android: crbug.com/1223950.
Justin Cohen8bfb6b72020-07-27 18:22:25129#define MAYBE_MaximumRequests DISABLED_MaximumRequests
130#else
131#define MAYBE_MaximumRequests MaximumRequests
132#endif
133TEST_F(ThroughputAnalyzerTest, MAYBE_MaximumRequests) {
Matt Menkea7e697122019-11-06 00:47:57134 const struct TestCase {
135 GURL url;
136 bool is_local;
137 } kTestCases[] = {
138 {GURL("http://127.0.0.1/test.html"), true /* is_local */},
139 {GURL("http://example.com/test.html"), false /* is_local */},
140 {GURL("http://local.com/test.html"), true /* is_local */},
141 };
tbansal80a52162016-05-20 17:55:04142
Matt Menkea7e697122019-11-06 00:47:57143 for (const auto& test_case : kTestCases) {
Greg Thompsonaa48ce8d2018-04-03 06:11:43144 const base::TickClock* tick_clock = base::DefaultTickClock::GetInstance();
Tarun Bansaled2b20b642018-10-15 19:51:32145 TestNetworkQualityEstimator network_quality_estimator;
tbansalff83205e2017-05-23 00:09:45146 std::map<std::string, std::string> variation_params;
tbansal4a4305a2017-06-08 05:03:19147 NetworkQualityEstimatorParams params(variation_params);
Tarun Bansaled2b20b642018-10-15 19:51:32148 TestThroughputAnalyzer throughput_analyzer(&network_quality_estimator,
tzik26331742017-12-07 07:28:33149 &params, tick_clock);
tbansal80a52162016-05-20 17:55:04150
151 TestDelegate test_delegate;
Yutaka Hirano36ab60c72022-03-17 08:30:37152 auto context_builder = CreateTestURLRequestContextBuilder();
153 context_builder->set_host_resolver(CreateMockHostResolver());
154 auto context = context_builder->Build();
tbansal80a52162016-05-20 17:55:04155
Jianfeng Wange829c4982019-07-03 21:17:09156 ASSERT_FALSE(
157 throughput_analyzer.disable_throughput_measurements_for_testing());
Brett Wilsonc6a0c822017-09-12 00:04:29158 base::circular_deque<std::unique_ptr<URLRequest>> requests;
tbansal80a52162016-05-20 17:55:04159
160 // Start more requests than the maximum number of requests that can be held
161 // in the memory.
Matt Menkea7e697122019-11-06 00:47:57162 EXPECT_EQ(test_case.is_local,
163 nqe::internal::IsPrivateHostForTesting(
Yutaka Hirano36ab60c72022-03-17 08:30:37164 context->host_resolver(),
165 HostPortPair::FromURL(test_case.url), NetworkIsolationKey()));
tbansal80a52162016-05-20 17:55:04166 for (size_t i = 0; i < 1000; ++i) {
167 std::unique_ptr<URLRequest> request(
Yutaka Hirano36ab60c72022-03-17 08:30:37168 context->CreateRequest(test_case.url, DEFAULT_PRIORITY,
169 &test_delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
tbansal80a52162016-05-20 17:55:04170 throughput_analyzer.NotifyStartTransaction(*(request.get()));
171 requests.push_back(std::move(request));
172 }
173 // Too many local requests should cause the |throughput_analyzer| to disable
174 // throughput measurements.
Matt Menkea7e697122019-11-06 00:47:57175 EXPECT_NE(test_case.is_local,
176 throughput_analyzer.IsCurrentlyTrackingThroughput());
177 }
178}
179
Xiaohan Wang2a6845b2022-01-08 04:40:57180#if BUILDFLAG(IS_IOS)
Justin Cohen8bfb6b72020-07-27 18:22:25181// Flaky on iOS: crbug.com/672917.
182#define MAYBE_MaximumRequestsWithNetworkIsolationKey \
183 DISABLED_MaximumRequestsWithNetworkIsolationKey
184#else
185#define MAYBE_MaximumRequestsWithNetworkIsolationKey \
186 MaximumRequestsWithNetworkIsolationKey
187#endif
Matt Menkea7e697122019-11-06 00:47:57188// Make sure that the NetworkIsolationKey is respected when resolving a host
189// from the cache.
Justin Cohen8bfb6b72020-07-27 18:22:25190TEST_F(ThroughputAnalyzerTest, MAYBE_MaximumRequestsWithNetworkIsolationKey) {
Matt Menke4807a9a2020-11-21 00:14:41191 const SchemefulSite kSite(GURL("https://foo.test/"));
192 const net::NetworkIsolationKey kNetworkIsolationKey(kSite, kSite);
Matt Menkea7e697122019-11-06 00:47:57193 const GURL kUrl = GURL("http://foo.test/test.html");
194
195 base::test::ScopedFeatureList feature_list;
196 feature_list.InitAndEnableFeature(
197 features::kSplitHostCacheByNetworkIsolationKey);
198
199 for (bool use_network_isolation_key : {false, true}) {
200 const base::TickClock* tick_clock = base::DefaultTickClock::GetInstance();
201 TestNetworkQualityEstimator network_quality_estimator;
202 std::map<std::string, std::string> variation_params;
203 NetworkQualityEstimatorParams params(variation_params);
204 TestThroughputAnalyzer throughput_analyzer(&network_quality_estimator,
205 &params, tick_clock);
206
207 TestDelegate test_delegate;
Yutaka Hirano36ab60c72022-03-17 08:30:37208 auto context_builder = CreateTestURLRequestContextBuilder();
209 auto mock_host_resolver = std::make_unique<MockCachingHostResolver>();
Matt Menkea7e697122019-11-06 00:47:57210
211 // Add an entry to the host cache mapping kUrl to non-local IP when using an
212 // empty NetworkIsolationKey.
Yutaka Hirano36ab60c72022-03-17 08:30:37213 mock_host_resolver->rules()->AddRule(kUrl.host(), "1.2.3.4");
214 mock_host_resolver->LoadIntoCache(HostPortPair::FromURL(kUrl),
215 NetworkIsolationKey(), absl::nullopt);
Matt Menkea7e697122019-11-06 00:47:57216
217 // Add an entry to the host cache mapping kUrl to local IP when using
218 // kNetworkIsolationKey.
Yutaka Hirano36ab60c72022-03-17 08:30:37219 mock_host_resolver->rules()->ClearRules();
220 mock_host_resolver->rules()->AddRule(kUrl.host(), "127.0.0.1");
221 mock_host_resolver->LoadIntoCache(HostPortPair::FromURL(kUrl),
222 kNetworkIsolationKey, absl::nullopt);
Matt Menkea7e697122019-11-06 00:47:57223
Yutaka Hirano36ab60c72022-03-17 08:30:37224 context_builder->set_host_resolver(std::move(mock_host_resolver));
225 auto context = context_builder->Build();
Matt Menkea7e697122019-11-06 00:47:57226 ASSERT_FALSE(
227 throughput_analyzer.disable_throughput_measurements_for_testing());
228 base::circular_deque<std::unique_ptr<URLRequest>> requests;
229
230 // Start more requests than the maximum number of requests that can be held
231 // in the memory.
232 EXPECT_EQ(use_network_isolation_key,
233 nqe::internal::IsPrivateHostForTesting(
Yutaka Hirano36ab60c72022-03-17 08:30:37234 context->host_resolver(), HostPortPair::FromURL(kUrl),
Matt Menkea7e697122019-11-06 00:47:57235 use_network_isolation_key ? kNetworkIsolationKey
236 : NetworkIsolationKey()));
237 for (size_t i = 0; i < 1000; ++i) {
238 std::unique_ptr<URLRequest> request(
Yutaka Hirano36ab60c72022-03-17 08:30:37239 context->CreateRequest(kUrl, DEFAULT_PRIORITY, &test_delegate,
240 TRAFFIC_ANNOTATION_FOR_TESTS));
Matt Menkea7e697122019-11-06 00:47:57241 if (use_network_isolation_key)
Matt Menke3ab9c7b2020-04-01 22:39:57242 request->set_isolation_info(IsolationInfo::CreatePartial(
shivanigithub4e78015f592020-10-21 13:26:23243 IsolationInfo::RequestType::kOther, kNetworkIsolationKey));
Matt Menkea7e697122019-11-06 00:47:57244 throughput_analyzer.NotifyStartTransaction(*(request.get()));
245 requests.push_back(std::move(request));
246 }
247 // Too many local requests should cause the |throughput_analyzer| to disable
248 // throughput measurements.
249 EXPECT_NE(use_network_isolation_key,
tbansal82edab42017-06-19 05:55:25250 throughput_analyzer.IsCurrentlyTrackingThroughput());
tbansal80a52162016-05-20 17:55:04251 }
252}
253
Tarun Bansalfc13d5982017-09-12 01:58:25254// Tests that the throughput observation is taken only if there are sufficient
255// number of requests in-flight.
Bence Béky98447b12018-05-08 03:14:01256TEST_F(ThroughputAnalyzerTest, TestMinRequestsForThroughputSample) {
Greg Thompsonaa48ce8d2018-04-03 06:11:43257 const base::TickClock* tick_clock = base::DefaultTickClock::GetInstance();
Tarun Bansaled2b20b642018-10-15 19:51:32258 TestNetworkQualityEstimator network_quality_estimator;
Tarun Bansalfc13d5982017-09-12 01:58:25259 std::map<std::string, std::string> variation_params;
Tarun Bansalf67b3e72018-03-02 06:10:33260 variation_params["throughput_hanging_requests_cwnd_size_multiplier"] = "-1";
Tarun Bansalfc13d5982017-09-12 01:58:25261 NetworkQualityEstimatorParams params(variation_params);
Tarun Bansalf67b3e72018-03-02 06:10:33262 // Set HTTP RTT to a large value so that the throughput observation window
263 // is not detected as hanging. In practice, this would be provided by
Tarun Bansaled2b20b642018-10-15 19:51:32264 // |network_quality_estimator| based on the recent observations.
Peter Kastinge5a38ed2021-10-02 03:06:35265 network_quality_estimator.SetStartTimeNullHttpRtt(base::Seconds(100));
Tarun Bansalfc13d5982017-09-12 01:58:25266
267 for (size_t num_requests = 1;
268 num_requests <= params.throughput_min_requests_in_flight() + 1;
269 ++num_requests) {
Tarun Bansaled2b20b642018-10-15 19:51:32270 TestThroughputAnalyzer throughput_analyzer(&network_quality_estimator,
tzik26331742017-12-07 07:28:33271 &params, tick_clock);
Yutaka Hirano36ab60c72022-03-17 08:30:37272 auto context_builder = CreateTestURLRequestContextBuilder();
273 context_builder->set_host_resolver(CreateMockHostResolver());
274 auto context = context_builder->Build();
Tarun Bansalfc13d5982017-09-12 01:58:25275 std::vector<std::unique_ptr<URLRequest>> requests_not_local;
276
Wez0e717112018-06-18 23:09:22277 std::vector<TestDelegate> not_local_test_delegates(num_requests);
Tsuyoshi Horo17ef47d02022-06-30 10:58:27278 for (auto& delegate : not_local_test_delegates) {
Wez0e717112018-06-18 23:09:22279 // We don't care about completion, except for the first one (see below).
Tsuyoshi Horo17ef47d02022-06-30 10:58:27280 delegate.set_on_complete(base::DoNothing());
Yutaka Hirano36ab60c72022-03-17 08:30:37281 std::unique_ptr<URLRequest> request_not_local(context->CreateRequest(
Tsuyoshi Horo17ef47d02022-06-30 10:58:27282 GURL("http://example.com/echo.html"), DEFAULT_PRIORITY, &delegate,
283 TRAFFIC_ANNOTATION_FOR_TESTS));
Tarun Bansalfc13d5982017-09-12 01:58:25284 request_not_local->Start();
285 requests_not_local.push_back(std::move(request_not_local));
286 }
Wez0e717112018-06-18 23:09:22287 not_local_test_delegates[0].RunUntilComplete();
Tarun Bansalfc13d5982017-09-12 01:58:25288
289 EXPECT_EQ(0, throughput_analyzer.throughput_observations_received());
290
Tsuyoshi Horo17ef47d02022-06-30 10:58:27291 for (const auto& request : requests_not_local) {
292 throughput_analyzer.NotifyStartTransaction(*request);
Tarun Bansalfc13d5982017-09-12 01:58:25293 }
294
295 // Increment the bytes received count to emulate the bytes received for
296 // |request_local| and |requests_not_local|.
297 throughput_analyzer.IncrementBitsReceived(100 * 1000 * 8);
298
Tsuyoshi Horo17ef47d02022-06-30 10:58:27299 for (const auto& request : requests_not_local) {
300 throughput_analyzer.NotifyRequestCompleted(*request);
Tarun Bansalfc13d5982017-09-12 01:58:25301 }
302 base::RunLoop().RunUntilIdle();
303
304 int expected_throughput_observations =
305 num_requests >= params.throughput_min_requests_in_flight() ? 1 : 0;
306 EXPECT_EQ(expected_throughput_observations,
307 throughput_analyzer.throughput_observations_received());
308 }
309}
310
Tarun Bansal00943112017-10-10 22:49:14311// Tests that the hanging requests are dropped from the |requests_|, and
312// throughput observation window is ended.
Bence Béky98447b12018-05-08 03:14:01313TEST_F(ThroughputAnalyzerTest, TestHangingRequests) {
Tarun Bansal00943112017-10-10 22:49:14314 static const struct {
315 int hanging_request_duration_http_rtt_multiplier;
316 base::TimeDelta http_rtt;
317 base::TimeDelta requests_hang_duration;
318 bool expect_throughput_observation;
319 } tests[] = {
320 {
321 // |requests_hang_duration| is less than 5 times the HTTP RTT.
322 // Requests should not be marked as hanging.
Peter Kastinge5a38ed2021-10-02 03:06:35323 5,
324 base::Milliseconds(1000),
325 base::Milliseconds(3000),
326 true,
Tarun Bansal00943112017-10-10 22:49:14327 },
328 {
329 // |requests_hang_duration| is more than 5 times the HTTP RTT.
330 // Requests should be marked as hanging.
Peter Kastinge5a38ed2021-10-02 03:06:35331 5,
332 base::Milliseconds(200),
333 base::Milliseconds(3000),
334 false,
Tarun Bansal00943112017-10-10 22:49:14335 },
336 {
337 // |requests_hang_duration| is less than
338 // |hanging_request_min_duration_msec|. Requests should not be marked
339 // as hanging.
Peter Kastinge5a38ed2021-10-02 03:06:35340 1,
341 base::Milliseconds(100),
342 base::Milliseconds(100),
343 true,
Tarun Bansal00943112017-10-10 22:49:14344 },
345 {
346 // |requests_hang_duration| is more than
347 // |hanging_request_min_duration_msec|. Requests should be marked as
348 // hanging.
Peter Kastinge5a38ed2021-10-02 03:06:35349 1,
350 base::Milliseconds(2000),
351 base::Milliseconds(3100),
352 false,
Tarun Bansal00943112017-10-10 22:49:14353 },
354 {
355 // |requests_hang_duration| is less than 5 times the HTTP RTT.
356 // Requests should not be marked as hanging.
Peter Kastinge5a38ed2021-10-02 03:06:35357 5,
358 base::Seconds(2),
359 base::Seconds(1),
Tarun Bansal00943112017-10-10 22:49:14360 true,
361 },
362 {
363 // HTTP RTT is unavailable. Requests should not be marked as hanging.
Peter Kastinge5a38ed2021-10-02 03:06:35364 5,
365 base::Seconds(-1),
366 base::Seconds(-1),
Tarun Bansal00943112017-10-10 22:49:14367 true,
368 },
369 };
370
371 for (const auto& test : tests) {
372 base::HistogramTester histogram_tester;
Greg Thompsonaa48ce8d2018-04-03 06:11:43373 const base::TickClock* tick_clock = base::DefaultTickClock::GetInstance();
Tarun Bansaled2b20b642018-10-15 19:51:32374 TestNetworkQualityEstimator network_quality_estimator;
Tarun Bansal00943112017-10-10 22:49:14375 if (test.http_rtt >= base::TimeDelta())
Tarun Bansaled2b20b642018-10-15 19:51:32376 network_quality_estimator.SetStartTimeNullHttpRtt(test.http_rtt);
Tarun Bansal00943112017-10-10 22:49:14377 std::map<std::string, std::string> variation_params;
Tarun Bansalf67b3e72018-03-02 06:10:33378 // Set the transport RTT multiplier to a large value so that the hanging
379 // request decision is made only on the basis of the HTTP RTT.
380 variation_params
381 ["hanging_request_http_rtt_upper_bound_transport_rtt_multiplier"] =
382 "10000";
383 variation_params["throughput_hanging_requests_cwnd_size_multiplier"] = "-1";
Tarun Bansal00943112017-10-10 22:49:14384 variation_params["hanging_request_duration_http_rtt_multiplier"] =
Raul Tambre8c1981d2019-02-08 02:22:26385 base::NumberToString(test.hanging_request_duration_http_rtt_multiplier);
Tarun Bansal00943112017-10-10 22:49:14386
387 NetworkQualityEstimatorParams params(variation_params);
388
389 const size_t num_requests = params.throughput_min_requests_in_flight();
Tarun Bansaled2b20b642018-10-15 19:51:32390 TestThroughputAnalyzer throughput_analyzer(&network_quality_estimator,
tzik26331742017-12-07 07:28:33391 &params, tick_clock);
Yutaka Hirano36ab60c72022-03-17 08:30:37392 auto context_builder = CreateTestURLRequestContextBuilder();
393 context_builder->set_host_resolver(CreateMockHostResolver());
394 auto context = context_builder->Build();
Tarun Bansal00943112017-10-10 22:49:14395 std::vector<std::unique_ptr<URLRequest>> requests_not_local;
396
Wez0e717112018-06-18 23:09:22397 std::vector<TestDelegate> not_local_test_delegates(num_requests);
Tarun Bansal00943112017-10-10 22:49:14398 for (size_t i = 0; i < num_requests; ++i) {
Wez0e717112018-06-18 23:09:22399 // We don't care about completion, except for the first one (see below).
400 not_local_test_delegates[i].set_on_complete(base::DoNothing());
Yutaka Hirano36ab60c72022-03-17 08:30:37401 std::unique_ptr<URLRequest> request_not_local(context->CreateRequest(
Tarun Bansal00943112017-10-10 22:49:14402 GURL("http://example.com/echo.html"), DEFAULT_PRIORITY,
Wez0e717112018-06-18 23:09:22403 &not_local_test_delegates[i], TRAFFIC_ANNOTATION_FOR_TESTS));
Tarun Bansal00943112017-10-10 22:49:14404 request_not_local->Start();
405 requests_not_local.push_back(std::move(request_not_local));
406 }
407
Wez0e717112018-06-18 23:09:22408 not_local_test_delegates[0].RunUntilComplete();
Tarun Bansal00943112017-10-10 22:49:14409
410 EXPECT_EQ(0, throughput_analyzer.throughput_observations_received());
411
412 for (size_t i = 0; i < num_requests; ++i) {
413 throughput_analyzer.NotifyStartTransaction(*requests_not_local.at(i));
414 }
415
416 // Increment the bytes received count to emulate the bytes received for
417 // |request_local| and |requests_not_local|.
418 throughput_analyzer.IncrementBitsReceived(100 * 1000 * 8);
419
420 // Mark in-flight requests as hanging requests (if specified in the test
421 // params).
422 if (test.requests_hang_duration >= base::TimeDelta())
423 base::PlatformThread::Sleep(test.requests_hang_duration);
424
Jianfeng Wang25d28452019-07-17 00:35:21425 EXPECT_EQ(num_requests, throughput_analyzer.CountActiveInFlightRequests());
Tarun Bansal00943112017-10-10 22:49:14426
427 for (size_t i = 0; i < num_requests; ++i) {
428 throughput_analyzer.NotifyRequestCompleted(*requests_not_local.at(i));
429 if (!test.expect_throughput_observation) {
430 // All in-flight requests should be marked as hanging, and thus should
431 // be deleted from the set of in-flight requests.
Jianfeng Wang25d28452019-07-17 00:35:21432 EXPECT_EQ(0u, throughput_analyzer.CountActiveInFlightRequests());
Tarun Bansal00943112017-10-10 22:49:14433 } else {
434 // One request should be deleted at one time.
435 EXPECT_EQ(requests_not_local.size() - i - 1,
Jianfeng Wang25d28452019-07-17 00:35:21436 throughput_analyzer.CountActiveInFlightRequests());
Tarun Bansal00943112017-10-10 22:49:14437 }
438 }
439
440 base::RunLoop().RunUntilIdle();
441
442 EXPECT_EQ(test.expect_throughput_observation,
443 throughput_analyzer.throughput_observations_received() > 0);
Tarun Bansal00943112017-10-10 22:49:14444 }
445}
446
447// Tests that the check for hanging requests is done at most once per second.
Bence Béky98447b12018-05-08 03:14:01448TEST_F(ThroughputAnalyzerTest, TestHangingRequestsCheckedOnlyPeriodically) {
Tarun Bansal00943112017-10-10 22:49:14449 base::SimpleTestTickClock tick_clock;
450
Tarun Bansaled2b20b642018-10-15 19:51:32451 TestNetworkQualityEstimator network_quality_estimator;
Peter Kastinge5a38ed2021-10-02 03:06:35452 network_quality_estimator.SetStartTimeNullHttpRtt(base::Seconds(1));
Tarun Bansal00943112017-10-10 22:49:14453 std::map<std::string, std::string> variation_params;
454 variation_params["hanging_request_duration_http_rtt_multiplier"] = "5";
455 variation_params["hanging_request_min_duration_msec"] = "2000";
456 NetworkQualityEstimatorParams params(variation_params);
457
Tarun Bansaled2b20b642018-10-15 19:51:32458 TestThroughputAnalyzer throughput_analyzer(&network_quality_estimator,
459 &params, &tick_clock);
Tarun Bansal00943112017-10-10 22:49:14460
461 TestDelegate test_delegate;
Yutaka Hirano36ab60c72022-03-17 08:30:37462 auto context_builder = CreateTestURLRequestContextBuilder();
463 context_builder->set_host_resolver(CreateMockHostResolver());
464 auto context = context_builder->Build();
Tarun Bansal00943112017-10-10 22:49:14465 std::vector<std::unique_ptr<URLRequest>> requests_not_local;
466
467 for (size_t i = 0; i < 2; ++i) {
Yutaka Hirano36ab60c72022-03-17 08:30:37468 std::unique_ptr<URLRequest> request_not_local(context->CreateRequest(
Tarun Bansal00943112017-10-10 22:49:14469 GURL("http://example.com/echo.html"), DEFAULT_PRIORITY, &test_delegate,
470 TRAFFIC_ANNOTATION_FOR_TESTS));
471 request_not_local->Start();
472 requests_not_local.push_back(std::move(request_not_local));
473 }
474
Yutaka Hirano36ab60c72022-03-17 08:30:37475 std::unique_ptr<URLRequest> some_other_request(context->CreateRequest(
Tarun Bansal00943112017-10-10 22:49:14476 GURL("http://example.com/echo.html"), DEFAULT_PRIORITY, &test_delegate,
477 TRAFFIC_ANNOTATION_FOR_TESTS));
478
Wez2a31b222018-06-07 22:07:15479 test_delegate.RunUntilComplete();
Tarun Bansal00943112017-10-10 22:49:14480
481 // First request starts at t=1. The second request starts at t=2. The first
482 // request would be marked as hanging at t=6, and the second request at t=7
483 // seconds.
484 for (size_t i = 0; i < 2; ++i) {
Peter Kastinge5a38ed2021-10-02 03:06:35485 tick_clock.Advance(base::Milliseconds(1000));
Tarun Bansal00943112017-10-10 22:49:14486 throughput_analyzer.NotifyStartTransaction(*requests_not_local.at(i));
487 }
488
Jianfeng Wang25d28452019-07-17 00:35:21489 EXPECT_EQ(2u, throughput_analyzer.CountActiveInFlightRequests());
Peter Kastinge5a38ed2021-10-02 03:06:35490 tick_clock.Advance(base::Milliseconds(3500));
Tarun Bansal00943112017-10-10 22:49:14491 // Current time is t = 5.5 seconds.
492 throughput_analyzer.EraseHangingRequests(*some_other_request);
Jianfeng Wang25d28452019-07-17 00:35:21493 EXPECT_EQ(2u, throughput_analyzer.CountActiveInFlightRequests());
Tarun Bansal00943112017-10-10 22:49:14494
Peter Kastinge5a38ed2021-10-02 03:06:35495 tick_clock.Advance(base::Milliseconds(1000));
Tarun Bansal00943112017-10-10 22:49:14496 // Current time is t = 6.5 seconds. One request should be marked as hanging.
497 throughput_analyzer.EraseHangingRequests(*some_other_request);
Jianfeng Wang25d28452019-07-17 00:35:21498 EXPECT_EQ(1u, throughput_analyzer.CountActiveInFlightRequests());
Tarun Bansal00943112017-10-10 22:49:14499
500 // Current time is t = 6.5 seconds. Calling NotifyBytesRead again should not
501 // run the hanging request checker since the last check was at t=6.5 seconds.
502 throughput_analyzer.EraseHangingRequests(*some_other_request);
Jianfeng Wang25d28452019-07-17 00:35:21503 EXPECT_EQ(1u, throughput_analyzer.CountActiveInFlightRequests());
Tarun Bansal00943112017-10-10 22:49:14504
Peter Kastinge5a38ed2021-10-02 03:06:35505 tick_clock.Advance(base::Milliseconds(600));
Tarun Bansal00943112017-10-10 22:49:14506 // Current time is t = 7.1 seconds. Calling NotifyBytesRead again should not
507 // run the hanging request checker since the last check was at t=6.5 seconds
508 // (less than 1 second ago).
509 throughput_analyzer.EraseHangingRequests(*some_other_request);
Jianfeng Wang25d28452019-07-17 00:35:21510 EXPECT_EQ(1u, throughput_analyzer.CountActiveInFlightRequests());
Tarun Bansal00943112017-10-10 22:49:14511
Peter Kastinge5a38ed2021-10-02 03:06:35512 tick_clock.Advance(base::Milliseconds(400));
Tarun Bansal00943112017-10-10 22:49:14513 // Current time is t = 7.5 seconds. Calling NotifyBytesRead again should run
514 // the hanging request checker since the last check was at t=6.5 seconds (at
515 // least 1 second ago).
516 throughput_analyzer.EraseHangingRequests(*some_other_request);
Jianfeng Wang25d28452019-07-17 00:35:21517 EXPECT_EQ(0u, throughput_analyzer.CountActiveInFlightRequests());
Tarun Bansal00943112017-10-10 22:49:14518}
519
520// Tests that the last received time for a request is updated when data is
521// received for that request.
Bence Béky98447b12018-05-08 03:14:01522TEST_F(ThroughputAnalyzerTest, TestLastReceivedTimeIsUpdated) {
Tarun Bansal00943112017-10-10 22:49:14523 base::SimpleTestTickClock tick_clock;
524
Tarun Bansaled2b20b642018-10-15 19:51:32525 TestNetworkQualityEstimator network_quality_estimator;
Peter Kastinge5a38ed2021-10-02 03:06:35526 network_quality_estimator.SetStartTimeNullHttpRtt(base::Seconds(1));
Tarun Bansal00943112017-10-10 22:49:14527 std::map<std::string, std::string> variation_params;
528 variation_params["hanging_request_duration_http_rtt_multiplier"] = "5";
529 variation_params["hanging_request_min_duration_msec"] = "2000";
530 NetworkQualityEstimatorParams params(variation_params);
531
Tarun Bansaled2b20b642018-10-15 19:51:32532 TestThroughputAnalyzer throughput_analyzer(&network_quality_estimator,
533 &params, &tick_clock);
Tarun Bansal00943112017-10-10 22:49:14534
535 TestDelegate test_delegate;
Yutaka Hirano36ab60c72022-03-17 08:30:37536 auto context_builder = CreateTestURLRequestContextBuilder();
537 context_builder->set_host_resolver(CreateMockHostResolver());
538 auto context = context_builder->Build();
Tarun Bansal00943112017-10-10 22:49:14539
Yutaka Hirano36ab60c72022-03-17 08:30:37540 std::unique_ptr<URLRequest> request_not_local(context->CreateRequest(
Tarun Bansal00943112017-10-10 22:49:14541 GURL("http://example.com/echo.html"), DEFAULT_PRIORITY, &test_delegate,
542 TRAFFIC_ANNOTATION_FOR_TESTS));
543 request_not_local->Start();
544
Wez2a31b222018-06-07 22:07:15545 test_delegate.RunUntilComplete();
Tarun Bansal00943112017-10-10 22:49:14546
Yutaka Hirano36ab60c72022-03-17 08:30:37547 std::unique_ptr<URLRequest> some_other_request(context->CreateRequest(
Tarun Bansal00943112017-10-10 22:49:14548 GURL("http://example.com/echo.html"), DEFAULT_PRIORITY, &test_delegate,
549 TRAFFIC_ANNOTATION_FOR_TESTS));
550
551 // Start time for the request is t=0 second. The request will be marked as
552 // hanging at t=5 seconds.
553 throughput_analyzer.NotifyStartTransaction(*request_not_local);
554
Peter Kastinge5a38ed2021-10-02 03:06:35555 tick_clock.Advance(base::Milliseconds(4000));
Tarun Bansal00943112017-10-10 22:49:14556 // Current time is t=4.0 seconds.
557
558 throughput_analyzer.EraseHangingRequests(*some_other_request);
Jianfeng Wang25d28452019-07-17 00:35:21559 EXPECT_EQ(1u, throughput_analyzer.CountActiveInFlightRequests());
Tarun Bansal00943112017-10-10 22:49:14560
561 // The request will be marked as hanging at t=9 seconds.
562 throughput_analyzer.NotifyBytesRead(*request_not_local);
Peter Kastinge5a38ed2021-10-02 03:06:35563 tick_clock.Advance(base::Milliseconds(4000));
Tarun Bansal00943112017-10-10 22:49:14564 // Current time is t=8 seconds.
565 throughput_analyzer.EraseHangingRequests(*some_other_request);
Jianfeng Wang25d28452019-07-17 00:35:21566 EXPECT_EQ(1u, throughput_analyzer.CountActiveInFlightRequests());
Tarun Bansal00943112017-10-10 22:49:14567
Peter Kastinge5a38ed2021-10-02 03:06:35568 tick_clock.Advance(base::Milliseconds(2000));
Tarun Bansal00943112017-10-10 22:49:14569 // Current time is t=10 seconds.
570 throughput_analyzer.EraseHangingRequests(*some_other_request);
Jianfeng Wang25d28452019-07-17 00:35:21571 EXPECT_EQ(0u, throughput_analyzer.CountActiveInFlightRequests());
Tarun Bansal00943112017-10-10 22:49:14572}
573
574// Test that a request that has been hanging for a long time is deleted
575// immediately when EraseHangingRequests is called even if the last hanging
576// request check was done recently.
Bence Béky98447b12018-05-08 03:14:01577TEST_F(ThroughputAnalyzerTest, TestRequestDeletedImmediately) {
Tarun Bansal00943112017-10-10 22:49:14578 base::SimpleTestTickClock tick_clock;
579
Tarun Bansaled2b20b642018-10-15 19:51:32580 TestNetworkQualityEstimator network_quality_estimator;
Peter Kastinge5a38ed2021-10-02 03:06:35581 network_quality_estimator.SetStartTimeNullHttpRtt(base::Seconds(1));
Tarun Bansal00943112017-10-10 22:49:14582 std::map<std::string, std::string> variation_params;
583 variation_params["hanging_request_duration_http_rtt_multiplier"] = "2";
Tarun Bansal00943112017-10-10 22:49:14584 NetworkQualityEstimatorParams params(variation_params);
585
Tarun Bansaled2b20b642018-10-15 19:51:32586 TestThroughputAnalyzer throughput_analyzer(&network_quality_estimator,
587 &params, &tick_clock);
Tarun Bansal00943112017-10-10 22:49:14588
589 TestDelegate test_delegate;
Yutaka Hirano36ab60c72022-03-17 08:30:37590 auto context_builder = CreateTestURLRequestContextBuilder();
591 context_builder->set_host_resolver(CreateMockHostResolver());
592 auto context = context_builder->Build();
Tarun Bansal00943112017-10-10 22:49:14593
Yutaka Hirano36ab60c72022-03-17 08:30:37594 std::unique_ptr<URLRequest> request_not_local(context->CreateRequest(
Tarun Bansal00943112017-10-10 22:49:14595 GURL("http://example.com/echo.html"), DEFAULT_PRIORITY, &test_delegate,
596 TRAFFIC_ANNOTATION_FOR_TESTS));
597 request_not_local->Start();
598
Wez2a31b222018-06-07 22:07:15599 test_delegate.RunUntilComplete();
Tarun Bansal00943112017-10-10 22:49:14600
601 // Start time for the request is t=0 second. The request will be marked as
602 // hanging at t=2 seconds.
603 throughput_analyzer.NotifyStartTransaction(*request_not_local);
Jianfeng Wang25d28452019-07-17 00:35:21604 EXPECT_EQ(1u, throughput_analyzer.CountActiveInFlightRequests());
Tarun Bansal00943112017-10-10 22:49:14605
Peter Kastinge5a38ed2021-10-02 03:06:35606 tick_clock.Advance(base::Milliseconds(2900));
Tarun Bansal5b7386a62018-09-24 21:54:30607 // Current time is t=2.9 seconds.
Tarun Bansal00943112017-10-10 22:49:14608
609 throughput_analyzer.EraseHangingRequests(*request_not_local);
Jianfeng Wang25d28452019-07-17 00:35:21610 EXPECT_EQ(1u, throughput_analyzer.CountActiveInFlightRequests());
Tarun Bansal00943112017-10-10 22:49:14611
612 // |request_not_local| should be deleted since it has been idle for 2.4
613 // seconds.
Peter Kastinge5a38ed2021-10-02 03:06:35614 tick_clock.Advance(base::Milliseconds(500));
Tarun Bansal00943112017-10-10 22:49:14615 throughput_analyzer.NotifyBytesRead(*request_not_local);
Jianfeng Wang25d28452019-07-17 00:35:21616 EXPECT_EQ(0u, throughput_analyzer.CountActiveInFlightRequests());
Tarun Bansal00943112017-10-10 22:49:14617}
618
Xiaohan Wang2a6845b2022-01-08 04:40:57619#if BUILDFLAG(IS_IOS)
Justin Cohen8bfb6b72020-07-27 18:22:25620// Flaky on iOS: crbug.com/672917.
621#define MAYBE_TestThroughputWithMultipleRequestsOverlap \
622 DISABLED_TestThroughputWithMultipleRequestsOverlap
623#else
624#define MAYBE_TestThroughputWithMultipleRequestsOverlap \
625 TestThroughputWithMultipleRequestsOverlap
626#endif
tbansal80a52162016-05-20 17:55:04627// Tests if the throughput observation is taken correctly when local and network
628// requests overlap.
Justin Cohen8bfb6b72020-07-27 18:22:25629TEST_F(ThroughputAnalyzerTest,
630 MAYBE_TestThroughputWithMultipleRequestsOverlap) {
tbansal80a52162016-05-20 17:55:04631 static const struct {
632 bool start_local_request;
633 bool local_request_completes_first;
634 bool expect_throughput_observation;
635 } tests[] = {
636 {
637 false, false, true,
638 },
639 {
640 true, false, false,
641 },
642 {
643 true, true, true,
644 },
645 };
646
647 for (const auto& test : tests) {
Greg Thompsonaa48ce8d2018-04-03 06:11:43648 const base::TickClock* tick_clock = base::DefaultTickClock::GetInstance();
Tarun Bansaled2b20b642018-10-15 19:51:32649 TestNetworkQualityEstimator network_quality_estimator;
tbansal80a52162016-05-20 17:55:04650 // Localhost requests are not allowed for estimation purposes.
tbansalff83205e2017-05-23 00:09:45651 std::map<std::string, std::string> variation_params;
Tarun Bansalf67b3e72018-03-02 06:10:33652 variation_params["throughput_hanging_requests_cwnd_size_multiplier"] = "-1";
tbansal4a4305a2017-06-08 05:03:19653 NetworkQualityEstimatorParams params(variation_params);
Tarun Bansalf67b3e72018-03-02 06:10:33654
Tarun Bansaled2b20b642018-10-15 19:51:32655 TestThroughputAnalyzer throughput_analyzer(&network_quality_estimator,
tzik26331742017-12-07 07:28:33656 &params, tick_clock);
tbansal80a52162016-05-20 17:55:04657
Wez0e717112018-06-18 23:09:22658 TestDelegate local_delegate;
659 local_delegate.set_on_complete(base::DoNothing());
Yutaka Hirano36ab60c72022-03-17 08:30:37660 auto context_builder = CreateTestURLRequestContextBuilder();
661 context_builder->set_host_resolver(CreateMockHostResolver());
662 auto context = context_builder->Build();
tbansal80a52162016-05-20 17:55:04663 std::unique_ptr<URLRequest> request_local;
664
Tarun Bansalfc13d5982017-09-12 01:58:25665 std::vector<std::unique_ptr<URLRequest>> requests_not_local;
Wez0e717112018-06-18 23:09:22666 std::vector<TestDelegate> not_local_test_delegates(
667 params.throughput_min_requests_in_flight());
Tarun Bansalfc13d5982017-09-12 01:58:25668 for (size_t i = 0; i < params.throughput_min_requests_in_flight(); ++i) {
Wez0e717112018-06-18 23:09:22669 // We don't care about completion, except for the first one (see below).
670 not_local_test_delegates[i].set_on_complete(base::DoNothing());
Yutaka Hirano36ab60c72022-03-17 08:30:37671 std::unique_ptr<URLRequest> request_not_local(context->CreateRequest(
Tarun Bansalfc13d5982017-09-12 01:58:25672 GURL("http://example.com/echo.html"), DEFAULT_PRIORITY,
Wez0e717112018-06-18 23:09:22673 &not_local_test_delegates[i], TRAFFIC_ANNOTATION_FOR_TESTS));
Tarun Bansalfc13d5982017-09-12 01:58:25674 request_not_local->Start();
675 requests_not_local.push_back(std::move(request_not_local));
676 }
tbansal80a52162016-05-20 17:55:04677
678 if (test.start_local_request) {
Yutaka Hirano36ab60c72022-03-17 08:30:37679 request_local = context->CreateRequest(GURL("http://127.0.0.1/echo.html"),
680 DEFAULT_PRIORITY, &local_delegate,
681 TRAFFIC_ANNOTATION_FOR_TESTS);
tbansal80a52162016-05-20 17:55:04682 request_local->Start();
683 }
684
Wez0e717112018-06-18 23:09:22685 // Wait until the first not-local request completes.
686 not_local_test_delegates[0].RunUntilComplete();
tbansal80a52162016-05-20 17:55:04687
688 EXPECT_EQ(0, throughput_analyzer.throughput_observations_received());
689
690 // If |test.start_local_request| is true, then |request_local| starts
691 // before |request_not_local|, and ends after |request_not_local|. Thus,
692 // network quality estimator should not get a chance to record throughput
693 // observation from |request_not_local| because of ongoing local request
694 // at all times.
695 if (test.start_local_request)
696 throughput_analyzer.NotifyStartTransaction(*request_local);
Tarun Bansalfc13d5982017-09-12 01:58:25697
Tsuyoshi Horo17ef47d02022-06-30 10:58:27698 for (const auto& request : requests_not_local) {
699 throughput_analyzer.NotifyStartTransaction(*request);
Tarun Bansalfc13d5982017-09-12 01:58:25700 }
tbansal80a52162016-05-20 17:55:04701
702 if (test.local_request_completes_first) {
703 ASSERT_TRUE(test.start_local_request);
704 throughput_analyzer.NotifyRequestCompleted(*request_local);
705 }
706
707 // Increment the bytes received count to emulate the bytes received for
Tarun Bansalfc13d5982017-09-12 01:58:25708 // |request_local| and |requests_not_local|.
tbansal80a52162016-05-20 17:55:04709 throughput_analyzer.IncrementBitsReceived(100 * 1000 * 8);
710
Tsuyoshi Horo17ef47d02022-06-30 10:58:27711 for (const auto& request : requests_not_local) {
712 throughput_analyzer.NotifyRequestCompleted(*request);
Tarun Bansalfc13d5982017-09-12 01:58:25713 }
tbansal80a52162016-05-20 17:55:04714 if (test.start_local_request && !test.local_request_completes_first)
715 throughput_analyzer.NotifyRequestCompleted(*request_local);
716
Wez0e717112018-06-18 23:09:22717 // Pump the message loop to let analyzer tasks get processed.
tbansal80a52162016-05-20 17:55:04718 base::RunLoop().RunUntilIdle();
719
720 int expected_throughput_observations =
721 test.expect_throughput_observation ? 1 : 0;
722 EXPECT_EQ(expected_throughput_observations,
723 throughput_analyzer.throughput_observations_received());
724 }
725}
726
727// Tests if the throughput observation is taken correctly when two network
728// requests overlap.
Bence Béky98447b12018-05-08 03:14:01729TEST_F(ThroughputAnalyzerTest, TestThroughputWithNetworkRequestsOverlap) {
tbansal80a52162016-05-20 17:55:04730 static const struct {
tbansalff83205e2017-05-23 00:09:45731 size_t throughput_min_requests_in_flight;
732 size_t number_requests_in_flight;
tbansal80a52162016-05-20 17:55:04733 int64_t increment_bits;
734 bool expect_throughput_observation;
735 } tests[] = {
736 {
tbansalff83205e2017-05-23 00:09:45737 1, 2, 100 * 1000 * 8, true,
tbansal80a52162016-05-20 17:55:04738 },
739 {
tbansalff83205e2017-05-23 00:09:45740 3, 1, 100 * 1000 * 8, false,
741 },
742 {
743 3, 2, 100 * 1000 * 8, false,
744 },
745 {
746 3, 3, 100 * 1000 * 8, true,
747 },
748 {
749 3, 4, 100 * 1000 * 8, true,
750 },
751 {
752 1, 2, 1, false,
tbansal80a52162016-05-20 17:55:04753 },
754 };
755
756 for (const auto& test : tests) {
Greg Thompsonaa48ce8d2018-04-03 06:11:43757 const base::TickClock* tick_clock = base::DefaultTickClock::GetInstance();
Tarun Bansaled2b20b642018-10-15 19:51:32758 TestNetworkQualityEstimator network_quality_estimator;
tbansal80a52162016-05-20 17:55:04759 // Localhost requests are not allowed for estimation purposes.
tbansalff83205e2017-05-23 00:09:45760 std::map<std::string, std::string> variation_params;
761 variation_params["throughput_min_requests_in_flight"] =
Raul Tambre8c1981d2019-02-08 02:22:26762 base::NumberToString(test.throughput_min_requests_in_flight);
Tarun Bansalf67b3e72018-03-02 06:10:33763 variation_params["throughput_hanging_requests_cwnd_size_multiplier"] = "-1";
tbansal4a4305a2017-06-08 05:03:19764 NetworkQualityEstimatorParams params(variation_params);
Tarun Bansalf67b3e72018-03-02 06:10:33765 // Set HTTP RTT to a large value so that the throughput observation window
766 // is not detected as hanging. In practice, this would be provided by
Tarun Bansaled2b20b642018-10-15 19:51:32767 // |network_quality_estimator| based on the recent observations.
Peter Kastinge5a38ed2021-10-02 03:06:35768 network_quality_estimator.SetStartTimeNullHttpRtt(base::Seconds(100));
Tarun Bansalf67b3e72018-03-02 06:10:33769
Tarun Bansaled2b20b642018-10-15 19:51:32770 TestThroughputAnalyzer throughput_analyzer(&network_quality_estimator,
tzik26331742017-12-07 07:28:33771 &params, tick_clock);
Yutaka Hirano36ab60c72022-03-17 08:30:37772 auto context_builder = CreateTestURLRequestContextBuilder();
773 context_builder->set_host_resolver(CreateMockHostResolver());
774 auto context = context_builder->Build();
tbansal80a52162016-05-20 17:55:04775
776 EXPECT_EQ(0, throughput_analyzer.throughput_observations_received());
777
tbansalff83205e2017-05-23 00:09:45778 std::vector<std::unique_ptr<URLRequest>> requests_in_flight;
Wez0e717112018-06-18 23:09:22779 std::vector<TestDelegate> in_flight_test_delegates(
780 test.number_requests_in_flight);
tbansalff83205e2017-05-23 00:09:45781 for (size_t i = 0; i < test.number_requests_in_flight; ++i) {
Wez0e717112018-06-18 23:09:22782 // We don't care about completion, except for the first one (see below).
783 in_flight_test_delegates[i].set_on_complete(base::DoNothing());
Yutaka Hirano36ab60c72022-03-17 08:30:37784 std::unique_ptr<URLRequest> request_network_1 = context->CreateRequest(
tbansalff83205e2017-05-23 00:09:45785 GURL("http://example.com/echo.html"), DEFAULT_PRIORITY,
Wez0e717112018-06-18 23:09:22786 &in_flight_test_delegates[i], TRAFFIC_ANNOTATION_FOR_TESTS);
tbansalff83205e2017-05-23 00:09:45787 requests_in_flight.push_back(std::move(request_network_1));
788 requests_in_flight.back()->Start();
789 }
tbansal80a52162016-05-20 17:55:04790
Wez0e717112018-06-18 23:09:22791 in_flight_test_delegates[0].RunUntilComplete();
tbansal80a52162016-05-20 17:55:04792
tbansalff83205e2017-05-23 00:09:45793 EXPECT_EQ(0, throughput_analyzer.throughput_observations_received());
tbansal80a52162016-05-20 17:55:04794
tbansalff83205e2017-05-23 00:09:45795 for (size_t i = 0; i < test.number_requests_in_flight; ++i) {
796 URLRequest* request = requests_in_flight.at(i).get();
797 throughput_analyzer.NotifyStartTransaction(*request);
798 }
tbansal80a52162016-05-20 17:55:04799
800 // Increment the bytes received count to emulate the bytes received for
801 // |request_network_1| and |request_network_2|.
802 throughput_analyzer.IncrementBitsReceived(test.increment_bits);
803
tbansalff83205e2017-05-23 00:09:45804 for (size_t i = 0; i < test.number_requests_in_flight; ++i) {
805 URLRequest* request = requests_in_flight.at(i).get();
806 throughput_analyzer.NotifyRequestCompleted(*request);
807 }
808
tbansal80a52162016-05-20 17:55:04809 base::RunLoop().RunUntilIdle();
810
811 // Only one observation should be taken since two requests overlap.
812 if (test.expect_throughput_observation) {
813 EXPECT_EQ(1, throughput_analyzer.throughput_observations_received());
814 } else {
815 EXPECT_EQ(0, throughput_analyzer.throughput_observations_received());
816 }
817 }
818}
819
tbansalff83205e2017-05-23 00:09:45820// Tests if the throughput observation is taken correctly when the start and end
821// of network requests overlap, and the minimum number of in flight requests
822// when taking an observation is more than 1.
Bence Béky98447b12018-05-08 03:14:01823TEST_F(ThroughputAnalyzerTest, TestThroughputWithMultipleNetworkRequests) {
Wez9d5dd282020-02-10 17:21:22824 const base::test::ScopedRunLoopTimeout increased_run_timeout(
Weza3ec3fe2020-02-17 12:52:16825 FROM_HERE, TestTimeouts::action_max_timeout());
Wez92e1e1332019-09-19 21:57:56826
Greg Thompsonaa48ce8d2018-04-03 06:11:43827 const base::TickClock* tick_clock = base::DefaultTickClock::GetInstance();
Tarun Bansaled2b20b642018-10-15 19:51:32828 TestNetworkQualityEstimator network_quality_estimator;
tbansalff83205e2017-05-23 00:09:45829 std::map<std::string, std::string> variation_params;
830 variation_params["throughput_min_requests_in_flight"] = "3";
Tarun Bansalf67b3e72018-03-02 06:10:33831 variation_params["throughput_hanging_requests_cwnd_size_multiplier"] = "-1";
tbansal4a4305a2017-06-08 05:03:19832 NetworkQualityEstimatorParams params(variation_params);
Tarun Bansalf67b3e72018-03-02 06:10:33833 // Set HTTP RTT to a large value so that the throughput observation window
834 // is not detected as hanging. In practice, this would be provided by
Tarun Bansaled2b20b642018-10-15 19:51:32835 // |network_quality_estimator| based on the recent observations.
Peter Kastinge5a38ed2021-10-02 03:06:35836 network_quality_estimator.SetStartTimeNullHttpRtt(base::Seconds(100));
Tarun Bansalf67b3e72018-03-02 06:10:33837
Tarun Bansaled2b20b642018-10-15 19:51:32838 TestThroughputAnalyzer throughput_analyzer(&network_quality_estimator,
839 &params, tick_clock);
tbansalff83205e2017-05-23 00:09:45840 TestDelegate test_delegate;
Yutaka Hirano36ab60c72022-03-17 08:30:37841 auto context_builder = CreateTestURLRequestContextBuilder();
842 context_builder->set_host_resolver(CreateMockHostResolver());
843 auto context = context_builder->Build();
tbansalff83205e2017-05-23 00:09:45844
845 EXPECT_EQ(0, throughput_analyzer.throughput_observations_received());
846
Yutaka Hirano36ab60c72022-03-17 08:30:37847 std::unique_ptr<URLRequest> request_1 = context->CreateRequest(
tbansalff83205e2017-05-23 00:09:45848 GURL("http://example.com/echo.html"), DEFAULT_PRIORITY, &test_delegate,
849 TRAFFIC_ANNOTATION_FOR_TESTS);
Yutaka Hirano36ab60c72022-03-17 08:30:37850 std::unique_ptr<URLRequest> request_2 = context->CreateRequest(
tbansalff83205e2017-05-23 00:09:45851 GURL("http://example.com/echo.html"), DEFAULT_PRIORITY, &test_delegate,
852 TRAFFIC_ANNOTATION_FOR_TESTS);
Yutaka Hirano36ab60c72022-03-17 08:30:37853 std::unique_ptr<URLRequest> request_3 = context->CreateRequest(
tbansalff83205e2017-05-23 00:09:45854 GURL("http://example.com/echo.html"), DEFAULT_PRIORITY, &test_delegate,
855 TRAFFIC_ANNOTATION_FOR_TESTS);
Yutaka Hirano36ab60c72022-03-17 08:30:37856 std::unique_ptr<URLRequest> request_4 = context->CreateRequest(
tbansalff83205e2017-05-23 00:09:45857 GURL("http://example.com/echo.html"), DEFAULT_PRIORITY, &test_delegate,
858 TRAFFIC_ANNOTATION_FOR_TESTS);
859
860 request_1->Start();
861 request_2->Start();
862 request_3->Start();
863 request_4->Start();
864
Wez0e717112018-06-18 23:09:22865 // We dispatched four requests, so wait for four completions.
866 for (int i = 0; i < 4; ++i)
867 test_delegate.RunUntilComplete();
tbansalff83205e2017-05-23 00:09:45868
869 EXPECT_EQ(0, throughput_analyzer.throughput_observations_received());
870
871 throughput_analyzer.NotifyStartTransaction(*(request_1.get()));
872 throughput_analyzer.NotifyStartTransaction(*(request_2.get()));
873
874 const size_t increment_bits = 100 * 1000 * 8;
875
876 // Increment the bytes received count to emulate the bytes received for
877 // |request_1| and |request_2|.
878 throughput_analyzer.IncrementBitsReceived(increment_bits);
879
880 throughput_analyzer.NotifyRequestCompleted(*(request_1.get()));
881 base::RunLoop().RunUntilIdle();
Wez0e717112018-06-18 23:09:22882
tbansalff83205e2017-05-23 00:09:45883 // No observation should be taken since only 1 request is in flight.
884 EXPECT_EQ(0, throughput_analyzer.throughput_observations_received());
885
886 throughput_analyzer.NotifyStartTransaction(*(request_3.get()));
887 throughput_analyzer.NotifyStartTransaction(*(request_4.get()));
888 EXPECT_EQ(0, throughput_analyzer.throughput_observations_received());
889
890 // 3 requests are in flight which is at least as many as the minimum number of
891 // in flight requests required. An observation should be taken.
892 throughput_analyzer.IncrementBitsReceived(increment_bits);
893
894 // Only one observation should be taken since two requests overlap.
895 throughput_analyzer.NotifyRequestCompleted(*(request_2.get()));
896 base::RunLoop().RunUntilIdle();
897
898 EXPECT_EQ(1, throughput_analyzer.throughput_observations_received());
899 throughput_analyzer.NotifyRequestCompleted(*(request_3.get()));
900 throughput_analyzer.NotifyRequestCompleted(*(request_4.get()));
901 EXPECT_EQ(1, throughput_analyzer.throughput_observations_received());
902}
903
Bence Béky98447b12018-05-08 03:14:01904TEST_F(ThroughputAnalyzerTest, TestHangingWindow) {
Tarun Bansal8914dbba2017-12-12 21:03:59905 static constexpr size_t kCwndSizeKilobytes = 10 * 1.5;
906 static constexpr size_t kCwndSizeBits = kCwndSizeKilobytes * 1000 * 8;
907
908 base::SimpleTestTickClock tick_clock;
909
Tarun Bansaled2b20b642018-10-15 19:51:32910 TestNetworkQualityEstimator network_quality_estimator;
Tarun Bansal8914dbba2017-12-12 21:03:59911 int64_t http_rtt_msec = 1000;
Tarun Bansaled2b20b642018-10-15 19:51:32912 network_quality_estimator.SetStartTimeNullHttpRtt(
Peter Kastinge5a38ed2021-10-02 03:06:35913 base::Milliseconds(http_rtt_msec));
Tarun Bansal8914dbba2017-12-12 21:03:59914 std::map<std::string, std::string> variation_params;
915 variation_params["throughput_hanging_requests_cwnd_size_multiplier"] = "1";
916 NetworkQualityEstimatorParams params(variation_params);
917
Tarun Bansaled2b20b642018-10-15 19:51:32918 TestThroughputAnalyzer throughput_analyzer(&network_quality_estimator,
919 &params, &tick_clock);
Tarun Bansal8914dbba2017-12-12 21:03:59920
921 const struct {
922 size_t bits_received;
923 base::TimeDelta window_duration;
924 bool expected_hanging;
925 } tests[] = {
Peter Kastinge5a38ed2021-10-02 03:06:35926 {100, base::Milliseconds(http_rtt_msec), true},
927 {kCwndSizeBits - 1, base::Milliseconds(http_rtt_msec), true},
928 {kCwndSizeBits + 1, base::Milliseconds(http_rtt_msec), false},
929 {2 * (kCwndSizeBits - 1), base::Milliseconds(http_rtt_msec * 2), true},
930 {2 * (kCwndSizeBits + 1), base::Milliseconds(http_rtt_msec * 2), false},
931 {kCwndSizeBits / 2 - 1, base::Milliseconds(http_rtt_msec / 2), true},
932 {kCwndSizeBits / 2 + 1, base::Milliseconds(http_rtt_msec / 2), false},
Tarun Bansal8914dbba2017-12-12 21:03:59933 };
934
935 for (const auto& test : tests) {
936 base::HistogramTester histogram_tester;
937 double kbps = test.bits_received / test.window_duration.InMillisecondsF();
938 EXPECT_EQ(test.expected_hanging,
939 throughput_analyzer.IsHangingWindow(test.bits_received,
940 test.window_duration, kbps));
941
942 if (test.expected_hanging) {
943 histogram_tester.ExpectUniqueSample("NQE.ThroughputObservation.Hanging",
944 kbps, 1);
945 histogram_tester.ExpectTotalCount("NQE.ThroughputObservation.NotHanging",
946 0);
947 } else {
948 histogram_tester.ExpectTotalCount("NQE.ThroughputObservation.Hanging", 0);
949 histogram_tester.ExpectUniqueSample(
950 "NQE.ThroughputObservation.NotHanging", kbps, 1);
951 }
952 }
953}
954
tbansal80a52162016-05-20 17:55:04955} // namespace
956
Tsuyoshi Horo4f516be2022-06-14 11:53:13957} // namespace net::nqe