• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium Authors
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/socket/connect_job.h"
6 
7 #include "base/functional/bind.h"
8 #include "base/functional/callback.h"
9 #include "base/run_loop.h"
10 #include "base/test/task_environment.h"
11 #include "net/base/address_list.h"
12 #include "net/base/net_errors.h"
13 #include "net/base/request_priority.h"
14 #include "net/dns/public/resolve_error_info.h"
15 #include "net/log/test_net_log.h"
16 #include "net/log/test_net_log_util.h"
17 #include "net/socket/connect_job_test_util.h"
18 #include "net/socket/socket_tag.h"
19 #include "net/socket/socket_test_util.h"
20 #include "net/test/gtest_util.h"
21 #include "net/url_request/static_http_user_agent_settings.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 
24 namespace net {
25 namespace {
26 
27 class TestConnectJob : public ConnectJob {
28  public:
29   enum class JobType {
30     kSyncSuccess,
31     kAsyncSuccess,
32     kHung,
33   };
34 
TestConnectJob(JobType job_type,base::TimeDelta timeout_duration,const CommonConnectJobParams * common_connect_job_params,ConnectJob::Delegate * delegate)35   TestConnectJob(JobType job_type,
36                  base::TimeDelta timeout_duration,
37                  const CommonConnectJobParams* common_connect_job_params,
38                  ConnectJob::Delegate* delegate)
39       : ConnectJob(DEFAULT_PRIORITY,
40                    SocketTag(),
41                    timeout_duration,
42                    common_connect_job_params,
43                    delegate,
44                    nullptr /* net_log */,
45                    NetLogSourceType::TRANSPORT_CONNECT_JOB,
46                    NetLogEventType::TRANSPORT_CONNECT_JOB_CONNECT),
47         job_type_(job_type) {
48     switch (job_type_) {
49       case JobType::kSyncSuccess:
50         socket_data_provider_.set_connect_data(MockConnect(SYNCHRONOUS, OK));
51         return;
52       case JobType::kAsyncSuccess:
53         socket_data_provider_.set_connect_data(MockConnect(ASYNC, OK));
54         return;
55       case JobType::kHung:
56         socket_data_provider_.set_connect_data(
57             MockConnect(SYNCHRONOUS, ERR_IO_PENDING));
58         return;
59     }
60   }
61 
62   TestConnectJob(const TestConnectJob&) = delete;
63   TestConnectJob& operator=(const TestConnectJob&) = delete;
64 
65   // From ConnectJob:
GetLoadState() const66   LoadState GetLoadState() const override { return LOAD_STATE_IDLE; }
HasEstablishedConnection() const67   bool HasEstablishedConnection() const override { return false; }
GetResolveErrorInfo() const68   ResolveErrorInfo GetResolveErrorInfo() const override {
69     return ResolveErrorInfo(net::OK);
70   }
ConnectInternal()71   int ConnectInternal() override {
72     SetSocket(std::make_unique<MockTCPClientSocket>(
73                   AddressList(), net_log().net_log(), &socket_data_provider_),
74               std::nullopt /* dns_aliases */);
75     return socket()->Connect(base::BindOnce(
76         &TestConnectJob::NotifyDelegateOfCompletion, base::Unretained(this)));
77   }
ChangePriorityInternal(RequestPriority priority)78   void ChangePriorityInternal(RequestPriority priority) override {
79     last_seen_priority_ = priority;
80   }
81 
82   using ConnectJob::ResetTimer;
83 
84   // The priority seen during the most recent call to ChangePriorityInternal().
last_seen_priority() const85   RequestPriority last_seen_priority() const { return last_seen_priority_; }
86 
87  protected:
88   const JobType job_type_;
89   StaticSocketDataProvider socket_data_provider_;
90   RequestPriority last_seen_priority_ = DEFAULT_PRIORITY;
91 };
92 
93 class ConnectJobTest : public testing::Test {
94  public:
ConnectJobTest()95   ConnectJobTest()
96       : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME),
97         common_connect_job_params_(
98             /*client_socket_factory=*/nullptr,
99             /*host_resolver=*/nullptr,
100             /*http_auth_cache=*/nullptr,
101             /*http_auth_handler_factory=*/nullptr,
102             /*spdy_session_pool=*/nullptr,
103             /*quic_supported_versions=*/nullptr,
104             /*quic_session_pool=*/nullptr,
105             /*proxy_delegate=*/nullptr,
106             &http_user_agent_settings_,
107             /*ssl_client_context=*/nullptr,
108             /*socket_performance_watcher_factory=*/nullptr,
109             /*network_quality_estimator=*/nullptr,
110             NetLog::Get(),
111             /*websocket_endpoint_lock_manager=*/nullptr,
112             /*http_server_properties*/ nullptr,
113             /*alpn_protos=*/nullptr,
114             /*application_settings=*/nullptr,
115             /*ignore_certificate_errors=*/nullptr,
116             /*early_data_enabled=*/nullptr) {}
117   ~ConnectJobTest() override = default;
118 
119  protected:
120   base::test::TaskEnvironment task_environment_;
121   RecordingNetLogObserver net_log_observer_;
122   const StaticHttpUserAgentSettings http_user_agent_settings_ = {"*",
123                                                                  "test-ua"};
124   const CommonConnectJobParams common_connect_job_params_;
125   TestConnectJobDelegate delegate_;
126 };
127 
128 // Even though a timeout is specified, it doesn't time out on a synchronous
129 // completion.
TEST_F(ConnectJobTest,NoTimeoutOnSyncCompletion)130 TEST_F(ConnectJobTest, NoTimeoutOnSyncCompletion) {
131   TestConnectJob job(TestConnectJob::JobType::kSyncSuccess,
132                      base::Microseconds(1), &common_connect_job_params_,
133                      &delegate_);
134   EXPECT_THAT(job.Connect(), test::IsOk());
135 }
136 
137 // Even though a timeout is specified, it doesn't time out on an asynchronous
138 // completion.
TEST_F(ConnectJobTest,NoTimeoutOnAsyncCompletion)139 TEST_F(ConnectJobTest, NoTimeoutOnAsyncCompletion) {
140   TestConnectJob job(TestConnectJob::JobType::kAsyncSuccess, base::Minutes(1),
141                      &common_connect_job_params_, &delegate_);
142   ASSERT_THAT(job.Connect(), test::IsError(ERR_IO_PENDING));
143   EXPECT_THAT(delegate_.WaitForResult(), test::IsOk());
144 }
145 
146 // Job shouldn't timeout when passed a TimeDelta of zero.
TEST_F(ConnectJobTest,NoTimeoutWithNoTimeDelta)147 TEST_F(ConnectJobTest, NoTimeoutWithNoTimeDelta) {
148   TestConnectJob job(TestConnectJob::JobType::kHung, base::TimeDelta(),
149                      &common_connect_job_params_, &delegate_);
150   ASSERT_THAT(job.Connect(), test::IsError(ERR_IO_PENDING));
151   task_environment_.RunUntilIdle();
152   EXPECT_FALSE(delegate_.has_result());
153 }
154 
155 // Make sure that ChangePriority() works, and new priority is visible to
156 // subclasses during the SetPriorityInternal call.
TEST_F(ConnectJobTest,SetPriority)157 TEST_F(ConnectJobTest, SetPriority) {
158   TestConnectJob job(TestConnectJob::JobType::kAsyncSuccess,
159                      base::Microseconds(1), &common_connect_job_params_,
160                      &delegate_);
161   ASSERT_THAT(job.Connect(), test::IsError(ERR_IO_PENDING));
162 
163   job.ChangePriority(HIGHEST);
164   EXPECT_EQ(HIGHEST, job.priority());
165   EXPECT_EQ(HIGHEST, job.last_seen_priority());
166 
167   job.ChangePriority(MEDIUM);
168   EXPECT_EQ(MEDIUM, job.priority());
169   EXPECT_EQ(MEDIUM, job.last_seen_priority());
170 
171   EXPECT_THAT(delegate_.WaitForResult(), test::IsOk());
172 }
173 
TEST_F(ConnectJobTest,TimedOut)174 TEST_F(ConnectJobTest, TimedOut) {
175   const base::TimeDelta kTimeout = base::Hours(1);
176 
177   std::unique_ptr<TestConnectJob> job =
178       std::make_unique<TestConnectJob>(TestConnectJob::JobType::kHung, kTimeout,
179                                        &common_connect_job_params_, &delegate_);
180   ASSERT_THAT(job->Connect(), test::IsError(ERR_IO_PENDING));
181 
182   // Nothing should happen before the specified time.
183   task_environment_.FastForwardBy(kTimeout - base::Milliseconds(1));
184   base::RunLoop().RunUntilIdle();
185   EXPECT_FALSE(delegate_.has_result());
186 
187   // At which point the job should time out.
188   task_environment_.FastForwardBy(base::Milliseconds(1));
189   EXPECT_THAT(delegate_.WaitForResult(), test::IsError(ERR_TIMED_OUT));
190 
191   // Have to delete the job for it to log the end event.
192   job.reset();
193 
194   auto entries = net_log_observer_.GetEntries();
195 
196   EXPECT_EQ(6u, entries.size());
197   EXPECT_TRUE(LogContainsBeginEvent(entries, 0, NetLogEventType::CONNECT_JOB));
198   EXPECT_TRUE(LogContainsBeginEvent(
199       entries, 1, NetLogEventType::TRANSPORT_CONNECT_JOB_CONNECT));
200   EXPECT_TRUE(LogContainsEvent(entries, 2,
201                                NetLogEventType::CONNECT_JOB_SET_SOCKET,
202                                NetLogEventPhase::NONE));
203   EXPECT_TRUE(LogContainsEvent(entries, 3,
204                                NetLogEventType::CONNECT_JOB_TIMED_OUT,
205                                NetLogEventPhase::NONE));
206   EXPECT_TRUE(LogContainsEndEvent(
207       entries, 4, NetLogEventType::TRANSPORT_CONNECT_JOB_CONNECT));
208   EXPECT_TRUE(LogContainsEndEvent(entries, 5, NetLogEventType::CONNECT_JOB));
209 }
210 
TEST_F(ConnectJobTest,TimedOutWithRestartedTimer)211 TEST_F(ConnectJobTest, TimedOutWithRestartedTimer) {
212   const base::TimeDelta kTimeout = base::Hours(1);
213 
214   TestConnectJob job(TestConnectJob::JobType::kHung, kTimeout,
215                      &common_connect_job_params_, &delegate_);
216   ASSERT_THAT(job.Connect(), test::IsError(ERR_IO_PENDING));
217 
218   // Nothing should happen before the specified time.
219   task_environment_.FastForwardBy(kTimeout - base::Milliseconds(1));
220   base::RunLoop().RunUntilIdle();
221   EXPECT_FALSE(delegate_.has_result());
222 
223   // Make sure restarting the timer is respected.
224   job.ResetTimer(kTimeout);
225   task_environment_.FastForwardBy(kTimeout - base::Milliseconds(1));
226   base::RunLoop().RunUntilIdle();
227   EXPECT_FALSE(delegate_.has_result());
228 
229   task_environment_.FastForwardBy(base::Milliseconds(1));
230   EXPECT_THAT(delegate_.WaitForResult(), test::IsError(ERR_TIMED_OUT));
231 }
232 
233 }  // namespace
234 }  // namespace net
235