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