| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/message_loop.h" | 5 #include "base/message_loop.h" |
| 6 #include "net/base/client_socket.h" | 6 #include "net/base/client_socket.h" |
| 7 #include "net/base/client_socket_factory.h" |
| 7 #include "net/base/client_socket_handle.h" | 8 #include "net/base/client_socket_handle.h" |
| 8 #include "net/base/client_socket_pool.h" | 9 #include "net/base/client_socket_pool.h" |
| 10 #include "net/base/host_resolver_unittest.h" |
| 9 #include "net/base/net_errors.h" | 11 #include "net/base/net_errors.h" |
| 12 #include "net/base/test_completion_callback.h" |
| 10 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
| 11 | 14 |
| 15 namespace net { |
| 16 |
| 12 namespace { | 17 namespace { |
| 13 | 18 |
| 14 const int kMaxSocketsPerGroup = 6; | 19 const int kMaxSocketsPerGroup = 6; |
| 15 | 20 |
| 16 // Note that the first and the last are the same, the first should be handled | 21 // Note that the first and the last are the same, the first should be handled |
| 17 // before the last, since it was inserted first. | 22 // before the last, since it was inserted first. |
| 18 const int kPriorities[10] = { 1, 7, 9, 5, 6, 2, 8, 3, 4, 1 }; | 23 const int kPriorities[10] = { 1, 7, 9, 5, 6, 2, 8, 3, 4, 1 }; |
| 19 | 24 |
| 20 // This is the number of extra requests beyond the first few that use up all | 25 // This is the number of extra requests beyond the first few that use up all |
| 21 // available sockets in the socket group. | 26 // available sockets in the socket group. |
| 22 const int kNumPendingRequests = arraysize(kPriorities); | 27 const int kNumPendingRequests = arraysize(kPriorities); |
| 23 | 28 |
| 24 class MockClientSocket : public net::ClientSocket { | 29 const int kNumRequests = kMaxSocketsPerGroup + kNumPendingRequests; |
| 30 |
| 31 class MockClientSocket : public ClientSocket { |
| 25 public: | 32 public: |
| 26 MockClientSocket() : connected_(false) { | 33 MockClientSocket() : connected_(false) {} |
| 27 allocation_count++; | |
| 28 } | |
| 29 | 34 |
| 30 // ClientSocket methods: | 35 // ClientSocket methods: |
| 31 virtual int Connect(net::CompletionCallback* callback) { | 36 virtual int Connect(CompletionCallback* callback) { |
| 32 connected_ = true; | 37 connected_ = true; |
| 33 return net::OK; | 38 return OK; |
| 34 } | 39 } |
| 35 virtual void Disconnect() { | 40 virtual void Disconnect() { |
| 36 connected_ = false; | 41 connected_ = false; |
| 37 } | 42 } |
| 38 virtual bool IsConnected() const { | 43 virtual bool IsConnected() const { |
| 39 return connected_; | 44 return connected_; |
| 40 } | 45 } |
| 41 virtual bool IsConnectedAndIdle() const { | 46 virtual bool IsConnectedAndIdle() const { |
| 42 return connected_; | 47 return connected_; |
| 43 } | 48 } |
| 44 | 49 |
| 45 // Socket methods: | 50 // Socket methods: |
| 46 virtual int Read(net::IOBuffer* buf, int buf_len, | 51 virtual int Read(IOBuffer* buf, int buf_len, |
| 47 net::CompletionCallback* callback) { | 52 CompletionCallback* callback) { |
| 48 return net::ERR_FAILED; | 53 return ERR_FAILED; |
| 49 } | 54 } |
| 50 virtual int Write(net::IOBuffer* buf, int buf_len, | 55 virtual int Write(IOBuffer* buf, int buf_len, |
| 51 net::CompletionCallback* callback) { | 56 CompletionCallback* callback) { |
| 52 return net::ERR_FAILED; | 57 return ERR_FAILED; |
| 53 } | 58 } |
| 54 | 59 |
| 55 static int allocation_count; | |
| 56 | |
| 57 private: | 60 private: |
| 58 bool connected_; | 61 bool connected_; |
| 59 }; | 62 }; |
| 60 | 63 |
| 61 int MockClientSocket::allocation_count = 0; | 64 class MockFailingClientSocket : public ClientSocket { |
| 65 public: |
| 66 MockFailingClientSocket() {} |
| 67 |
| 68 // ClientSocket methods: |
| 69 virtual int Connect(CompletionCallback* callback) { |
| 70 return ERR_CONNECTION_FAILED; |
| 71 } |
| 72 |
| 73 virtual void Disconnect() {} |
| 74 |
| 75 virtual bool IsConnected() const { |
| 76 return false; |
| 77 } |
| 78 virtual bool IsConnectedAndIdle() const { |
| 79 return false; |
| 80 } |
| 81 |
| 82 // Socket methods: |
| 83 virtual int Read(IOBuffer* buf, int buf_len, |
| 84 CompletionCallback* callback) { |
| 85 return ERR_FAILED; |
| 86 } |
| 87 |
| 88 virtual int Write(IOBuffer* buf, int buf_len, |
| 89 CompletionCallback* callback) { |
| 90 return ERR_FAILED; |
| 91 } |
| 92 }; |
| 93 |
| 94 class MockPendingClientSocket : public ClientSocket { |
| 95 public: |
| 96 MockPendingClientSocket() {} |
| 97 |
| 98 // ClientSocket methods: |
| 99 virtual int Connect(CompletionCallback* callback) { |
| 100 return ERR_IO_PENDING; |
| 101 } |
| 102 |
| 103 virtual void Disconnect() {} |
| 104 |
| 105 virtual bool IsConnected() const { |
| 106 return false; |
| 107 } |
| 108 virtual bool IsConnectedAndIdle() const { |
| 109 return false; |
| 110 } |
| 111 |
| 112 // Socket methods: |
| 113 virtual int Read(IOBuffer* buf, int buf_len, |
| 114 CompletionCallback* callback) { |
| 115 return ERR_FAILED; |
| 116 } |
| 117 |
| 118 virtual int Write(IOBuffer* buf, int buf_len, |
| 119 CompletionCallback* callback) { |
| 120 return ERR_FAILED; |
| 121 } |
| 122 }; |
| 123 |
| 124 class MockClientSocketFactory : public ClientSocketFactory { |
| 125 public: |
| 126 enum ClientSocketType { |
| 127 MOCK_CLIENT_SOCKET, |
| 128 MOCK_FAILING_CLIENT_SOCKET, |
| 129 MOCK_PENDING_CLIENT_SOCKET, |
| 130 }; |
| 131 |
| 132 MockClientSocketFactory() |
| 133 : allocation_count_(0), client_socket_type_(MOCK_CLIENT_SOCKET) {} |
| 134 |
| 135 virtual ClientSocket* CreateTCPClientSocket(const AddressList& addresses) { |
| 136 allocation_count_++; |
| 137 switch (client_socket_type_) { |
| 138 case MOCK_CLIENT_SOCKET: |
| 139 return new MockClientSocket(); |
| 140 case MOCK_FAILING_CLIENT_SOCKET: |
| 141 return new MockFailingClientSocket(); |
| 142 case MOCK_PENDING_CLIENT_SOCKET: |
| 143 return new MockPendingClientSocket(); |
| 144 default: |
| 145 NOTREACHED(); |
| 146 return new MockClientSocket(); |
| 147 } |
| 148 } |
| 149 |
| 150 virtual SSLClientSocket* CreateSSLClientSocket( |
| 151 ClientSocket* transport_socket, |
| 152 const std::string& hostname, |
| 153 const SSLConfig& ssl_config) { |
| 154 NOTIMPLEMENTED(); |
| 155 return NULL; |
| 156 } |
| 157 |
| 158 int allocation_count() const { return allocation_count_; } |
| 159 |
| 160 void set_client_socket_type(ClientSocketType type) { |
| 161 client_socket_type_ = type; |
| 162 } |
| 163 |
| 164 private: |
| 165 int allocation_count_; |
| 166 ClientSocketType client_socket_type_; |
| 167 }; |
| 62 | 168 |
| 63 class TestSocketRequest : public CallbackRunner< Tuple1<int> > { | 169 class TestSocketRequest : public CallbackRunner< Tuple1<int> > { |
| 64 public: | 170 public: |
| 65 TestSocketRequest( | 171 TestSocketRequest( |
| 66 net::ClientSocketPool* pool, | 172 ClientSocketPool* pool, |
| 67 std::vector<TestSocketRequest*>* request_order) | 173 std::vector<TestSocketRequest*>* request_order) |
| 68 : handle(pool), request_order_(request_order) {} | 174 : handle(pool), request_order_(request_order) {} |
| 69 | 175 |
| 70 net::ClientSocketHandle handle; | 176 ClientSocketHandle handle; |
| 71 | 177 |
| 72 void EnsureSocket() { | 178 int WaitForResult() { |
| 73 DCHECK(handle.is_initialized()); | 179 return callback_.WaitForResult(); |
| 74 request_order_->push_back(this); | |
| 75 if (!handle.socket()) { | |
| 76 handle.set_socket(new MockClientSocket()); | |
| 77 handle.socket()->Connect(NULL); | |
| 78 } | |
| 79 } | 180 } |
| 80 | 181 |
| 81 virtual void RunWithParams(const Tuple1<int>& params) { | 182 virtual void RunWithParams(const Tuple1<int>& params) { |
| 82 DCHECK(params.a == net::OK); | 183 callback_.RunWithParams(params); |
| 83 completion_count++; | 184 completion_count++; |
| 84 EnsureSocket(); | 185 request_order_->push_back(this); |
| 85 } | 186 } |
| 86 | 187 |
| 87 static int completion_count; | 188 static int completion_count; |
| 88 | 189 |
| 89 private: | 190 private: |
| 90 std::vector<TestSocketRequest*>* request_order_; | 191 std::vector<TestSocketRequest*>* request_order_; |
| 192 TestCompletionCallback callback_; |
| 91 }; | 193 }; |
| 92 | 194 |
| 93 int TestSocketRequest::completion_count = 0; | 195 int TestSocketRequest::completion_count = 0; |
| 94 | 196 |
| 95 class ClientSocketPoolTest : public testing::Test { | 197 class ClientSocketPoolTest : public testing::Test { |
| 96 protected: | 198 protected: |
| 97 ClientSocketPoolTest() | 199 ClientSocketPoolTest() |
| 98 : pool_(new net::ClientSocketPool(kMaxSocketsPerGroup)) {} | 200 : pool_(new ClientSocketPool(kMaxSocketsPerGroup, |
| 201 &client_socket_factory_)) {} |
| 99 | 202 |
| 100 virtual void SetUp() { | 203 virtual void SetUp() { |
| 101 MockClientSocket::allocation_count = 0; | |
| 102 TestSocketRequest::completion_count = 0; | 204 TestSocketRequest::completion_count = 0; |
| 103 } | 205 } |
| 104 | 206 |
| 105 scoped_refptr<net::ClientSocketPool> pool_; | 207 MockClientSocketFactory client_socket_factory_; |
| 208 scoped_refptr<ClientSocketPool> pool_; |
| 106 std::vector<TestSocketRequest*> request_order_; | 209 std::vector<TestSocketRequest*> request_order_; |
| 107 }; | 210 }; |
| 108 | 211 |
| 109 TEST_F(ClientSocketPoolTest, Basic) { | 212 TEST_F(ClientSocketPoolTest, Basic) { |
| 110 TestSocketRequest r(pool_.get(), &request_order_); | 213 TestCompletionCallback callback; |
| 111 int rv; | 214 ClientSocketHandle handle(pool_.get()); |
| 215 int rv = handle.Init("a", "www.google.com", 80, 0, &callback); |
| 216 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 217 EXPECT_FALSE(handle.is_initialized()); |
| 218 EXPECT_FALSE(handle.socket()); |
| 112 | 219 |
| 113 rv = r.handle.Init("a", 0, &r); | 220 EXPECT_EQ(OK, callback.WaitForResult()); |
| 114 EXPECT_EQ(net::OK, rv); | 221 EXPECT_TRUE(handle.is_initialized()); |
| 115 EXPECT_TRUE(r.handle.is_initialized()); | 222 EXPECT_TRUE(handle.socket()); |
| 116 | 223 |
| 117 r.handle.Reset(); | 224 handle.Reset(); |
| 118 | 225 |
| 119 // The handle's Reset method may have posted a task. | 226 // The handle's Reset method may have posted a task. |
| 120 MessageLoop::current()->RunAllPending(); | 227 MessageLoop::current()->RunAllPending(); |
| 121 } | 228 } |
| 122 | 229 |
| 123 TEST_F(ClientSocketPoolTest, WithIdleConnection) { | 230 TEST_F(ClientSocketPoolTest, InitHostResolutionFailure) { |
| 124 TestSocketRequest r(pool_.get(), &request_order_); | 231 RuleBasedHostMapper* host_mapper = new RuleBasedHostMapper; |
| 125 int rv; | 232 host_mapper->AddSimulatedFailure("unresolvable.host.name"); |
| 233 ScopedHostMapper scoped_host_mapper(host_mapper); |
| 234 TestSocketRequest req(pool_.get(), &request_order_); |
| 235 EXPECT_EQ(ERR_IO_PENDING, |
| 236 req.handle.Init("a", "unresolvable.host.name", 80, 5, &req)); |
| 237 EXPECT_EQ(ERR_NAME_NOT_RESOLVED, req.WaitForResult()); |
| 238 } |
| 126 | 239 |
| 127 rv = r.handle.Init("a", 0, &r); | 240 TEST_F(ClientSocketPoolTest, InitConnectionFailure) { |
| 128 EXPECT_EQ(net::OK, rv); | 241 client_socket_factory_.set_client_socket_type( |
| 129 EXPECT_TRUE(r.handle.is_initialized()); | 242 MockClientSocketFactory::MOCK_FAILING_CLIENT_SOCKET); |
| 130 | 243 TestSocketRequest req(pool_.get(), &request_order_); |
| 131 // Create a socket. | 244 EXPECT_EQ(ERR_IO_PENDING, |
| 132 r.EnsureSocket(); | 245 req.handle.Init("a", "unresolvable.host.name", 80, 5, &req)); |
| 133 | 246 EXPECT_EQ(ERR_CONNECTION_FAILED, req.WaitForResult()); |
| 134 // Release the socket. It should find its way into the idle list. We're | |
| 135 // testing that this does not trigger a crash. | |
| 136 r.handle.Reset(); | |
| 137 | |
| 138 // The handle's Reset method may have posted a task. | |
| 139 MessageLoop::current()->RunAllPending(); | |
| 140 } | 247 } |
| 141 | 248 |
| 142 TEST_F(ClientSocketPoolTest, PendingRequests) { | 249 TEST_F(ClientSocketPoolTest, PendingRequests) { |
| 143 int rv; | 250 int rv; |
| 144 | 251 |
| 145 scoped_ptr<TestSocketRequest> reqs[kMaxSocketsPerGroup + kNumPendingRequests]; | 252 scoped_ptr<TestSocketRequest> reqs[kNumRequests]; |
| 146 | 253 |
| 147 for (size_t i = 0; i < arraysize(reqs); ++i) | 254 for (size_t i = 0; i < arraysize(reqs); ++i) |
| 148 reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_)); | 255 reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_)); |
| 149 | 256 |
| 150 // Create connections or queue up requests. | 257 // Create connections or queue up requests. |
| 151 for (int i = 0; i < kMaxSocketsPerGroup; ++i) { | 258 for (int i = 0; i < kMaxSocketsPerGroup; ++i) { |
| 152 rv = reqs[i]->handle.Init("a", 5, reqs[i].get()); | 259 rv = reqs[i]->handle.Init("a", "www.google.com", 80, 5, reqs[i].get()); |
| 153 EXPECT_EQ(net::OK, rv); | 260 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 154 reqs[i]->EnsureSocket(); | 261 EXPECT_EQ(OK, reqs[i]->WaitForResult()); |
| 155 } | 262 } |
| 263 |
| 156 for (int i = 0; i < kNumPendingRequests; ++i) { | 264 for (int i = 0; i < kNumPendingRequests; ++i) { |
| 157 rv = reqs[kMaxSocketsPerGroup + i]->handle.Init( | 265 rv = reqs[kMaxSocketsPerGroup + i]->handle.Init( |
| 158 "a", kPriorities[i], reqs[kMaxSocketsPerGroup + i].get()); | 266 "a", "www.google.com", 80, kPriorities[i], |
| 159 EXPECT_EQ(net::ERR_IO_PENDING, rv); | 267 reqs[kMaxSocketsPerGroup + i].get()); |
| 268 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 160 } | 269 } |
| 161 | 270 |
| 162 // Release any connections until we have no connections. | 271 // Release any connections until we have no connections. |
| 163 bool released_one; | 272 bool released_one; |
| 164 do { | 273 do { |
| 165 released_one = false; | 274 released_one = false; |
| 166 for (size_t i = 0; i < arraysize(reqs); ++i) { | 275 for (size_t i = 0; i < arraysize(reqs); ++i) { |
| 167 if (reqs[i]->handle.is_initialized()) { | 276 if (reqs[i]->handle.is_initialized()) { |
| 168 reqs[i]->handle.Reset(); | 277 reqs[i]->handle.Reset(); |
| 169 MessageLoop::current()->RunAllPending(); | 278 MessageLoop::current()->RunAllPending(); |
| 170 released_one = true; | 279 released_one = true; |
| 171 } | 280 } |
| 172 } | 281 } |
| 173 } while (released_one); | 282 } while (released_one); |
| 174 | 283 |
| 175 EXPECT_EQ(kMaxSocketsPerGroup, MockClientSocket::allocation_count); | 284 EXPECT_EQ(kMaxSocketsPerGroup, client_socket_factory_.allocation_count()); |
| 176 EXPECT_EQ(kNumPendingRequests, TestSocketRequest::completion_count); | 285 EXPECT_EQ(kNumRequests, TestSocketRequest::completion_count); |
| 177 | 286 |
| 178 for (int i = 0; i < kMaxSocketsPerGroup; ++i) { | 287 for (int i = 0; i < kMaxSocketsPerGroup; ++i) { |
| 179 EXPECT_EQ(request_order_[i], reqs[i].get()) << | 288 EXPECT_EQ(request_order_[i], reqs[i].get()) << |
| 180 "Request " << i << " was not in order."; | 289 "Request " << i << " was not in order."; |
| 181 } | 290 } |
| 182 | 291 |
| 183 for (int i = 0; i < kNumPendingRequests - 1; ++i) { | 292 for (int i = 0; i < kNumPendingRequests - 1; ++i) { |
| 184 int index_in_queue = (kNumPendingRequests - 1) - kPriorities[i]; | 293 int index_in_queue = (kNumPendingRequests - 1) - kPriorities[i]; |
| 185 EXPECT_EQ(request_order_[kMaxSocketsPerGroup + index_in_queue], | 294 EXPECT_EQ(request_order_[kMaxSocketsPerGroup + index_in_queue], |
| 186 reqs[kMaxSocketsPerGroup + i].get()) << | 295 reqs[kMaxSocketsPerGroup + i].get()) << |
| 187 "Request " << kMaxSocketsPerGroup + i << " was not in order."; | 296 "Request " << kMaxSocketsPerGroup + i << " was not in order."; |
| 188 } | 297 } |
| 189 | 298 |
| 190 EXPECT_EQ(request_order_[arraysize(reqs) - 1], | 299 EXPECT_EQ(request_order_[arraysize(reqs) - 1], |
| 191 reqs[arraysize(reqs) - 1].get()) << | 300 reqs[arraysize(reqs) - 1].get()) << |
| 192 "The last request with priority 1 should not have been inserted " | 301 "The last request with priority 1 should not have been inserted " |
| 193 "earlier into the queue."; | 302 "earlier into the queue."; |
| 194 } | 303 } |
| 195 | 304 |
| 196 TEST_F(ClientSocketPoolTest, PendingRequests_NoKeepAlive) { | 305 TEST_F(ClientSocketPoolTest, PendingRequests_NoKeepAlive) { |
| 197 int rv; | 306 scoped_ptr<TestSocketRequest> reqs[kNumRequests]; |
| 198 | |
| 199 scoped_ptr<TestSocketRequest> reqs[kMaxSocketsPerGroup + kNumPendingRequests]; | |
| 200 for (size_t i = 0; i < arraysize(reqs); ++i) | 307 for (size_t i = 0; i < arraysize(reqs); ++i) |
| 201 reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_)); | 308 reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_)); |
| 202 | 309 |
| 203 // Create connections or queue up requests. | 310 // Create connections or queue up requests. |
| 204 for (size_t i = 0; i < arraysize(reqs); ++i) { | 311 for (int i = 0; i < kMaxSocketsPerGroup; ++i) { |
| 205 rv = reqs[i]->handle.Init("a", 0, reqs[i].get()); | 312 int rv = reqs[i]->handle.Init("a", "www.google.com", 80, 0, reqs[i].get()); |
| 206 if (rv != net::ERR_IO_PENDING) { | 313 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 207 EXPECT_EQ(net::OK, rv); | 314 EXPECT_EQ(OK, reqs[i]->WaitForResult()); |
| 208 reqs[i]->EnsureSocket(); | 315 } |
| 209 } | 316 |
| 317 for (int i = 0; i < kNumPendingRequests; ++i) { |
| 318 EXPECT_EQ(ERR_IO_PENDING, reqs[kMaxSocketsPerGroup + i]->handle.Init( |
| 319 "a", "www.google.com", 80, 0, reqs[kMaxSocketsPerGroup + i].get())); |
| 210 } | 320 } |
| 211 | 321 |
| 212 // Release any connections until we have no connections. | 322 // Release any connections until we have no connections. |
| 213 bool released_one; | 323 |
| 214 do { | 324 while (TestSocketRequest::completion_count < kNumRequests) { |
| 215 released_one = false; | 325 int num_released = 0; |
| 216 for (size_t i = 0; i < arraysize(reqs); ++i) { | 326 for (size_t i = 0; i < arraysize(reqs); ++i) { |
| 217 if (reqs[i]->handle.is_initialized()) { | 327 if (reqs[i]->handle.is_initialized()) { |
| 218 reqs[i]->handle.socket()->Disconnect(); | 328 reqs[i]->handle.socket()->Disconnect(); |
| 219 reqs[i]->handle.Reset(); | 329 reqs[i]->handle.Reset(); |
| 220 MessageLoop::current()->RunAllPending(); | 330 num_released++; |
| 221 released_one = true; | |
| 222 } | 331 } |
| 223 } | 332 } |
| 224 } while (released_one); | 333 int curr_num_completed = TestSocketRequest::completion_count; |
| 334 for (int i = 0; |
| 335 (i < num_released) && (i + curr_num_completed < kNumRequests); ++i) { |
| 336 EXPECT_EQ(OK, reqs[i + curr_num_completed]->WaitForResult()); |
| 337 } |
| 338 } |
| 225 | 339 |
| 226 EXPECT_EQ(kMaxSocketsPerGroup + kNumPendingRequests, | 340 EXPECT_EQ(kNumRequests, client_socket_factory_.allocation_count()); |
| 227 MockClientSocket::allocation_count); | 341 EXPECT_EQ(kNumRequests, TestSocketRequest::completion_count); |
| 228 EXPECT_EQ(kNumPendingRequests, TestSocketRequest::completion_count); | 342 } |
| 343 |
| 344 // This test will start up a RequestSocket() and then immediately Cancel() it. |
| 345 // The pending host resolution will eventually complete, and destroy the |
| 346 // ClientSocketPool which will crash if the group was not cleared properly. |
| 347 TEST_F(ClientSocketPoolTest, CancelRequestClearGroup) { |
| 348 TestSocketRequest req(pool_.get(), &request_order_); |
| 349 EXPECT_EQ(ERR_IO_PENDING, |
| 350 req.handle.Init("a", "www.google.com", 80, 5, &req)); |
| 351 req.handle.Reset(); |
| 352 |
| 353 PlatformThread::Sleep(100); |
| 354 |
| 355 // There is a race condition here. If the worker pool doesn't post the task |
| 356 // before we get here, then this might not run ConnectingSocket::OnIOComplete |
| 357 // and therefore leak the canceled ConnectingSocket. However, other tests |
| 358 // after this will call MessageLoop::RunAllPending() which should prevent a |
| 359 // leak, unless the worker thread takes longer than all of them. |
| 360 MessageLoop::current()->RunAllPending(); |
| 361 } |
| 362 |
| 363 TEST_F(ClientSocketPoolTest, TwoRequestsCancelOne) { |
| 364 TestSocketRequest req(pool_.get(), &request_order_); |
| 365 TestSocketRequest req2(pool_.get(), &request_order_); |
| 366 |
| 367 EXPECT_EQ(ERR_IO_PENDING, |
| 368 req.handle.Init("a", "www.google.com", 80, 5, &req)); |
| 369 EXPECT_EQ(ERR_IO_PENDING, |
| 370 req2.handle.Init("a", "www.google.com", 80, 5, &req)); |
| 371 |
| 372 req.handle.Reset(); |
| 373 PlatformThread::Sleep(100); |
| 374 |
| 375 // There is a benign race condition here. The worker pool may or may not post |
| 376 // the tasks before we get here. It won't test the case properly if it |
| 377 // doesn't, but 100ms should be enough most of the time. |
| 378 MessageLoop::current()->RunAllPending(); |
| 379 |
| 380 req2.handle.Reset(); |
| 381 // The handle's Reset method may have posted a task. |
| 382 MessageLoop::current()->RunAllPending(); |
| 383 } |
| 384 |
| 385 TEST_F(ClientSocketPoolTest, ConnectCancelConnect) { |
| 386 client_socket_factory_.set_client_socket_type( |
| 387 MockClientSocketFactory::MOCK_PENDING_CLIENT_SOCKET); |
| 388 TestSocketRequest req(pool_.get(), &request_order_); |
| 389 |
| 390 EXPECT_EQ(ERR_IO_PENDING, |
| 391 req.handle.Init("a", "www.google.com", 80, 5, &req)); |
| 392 |
| 393 req.handle.Reset(); |
| 394 |
| 395 EXPECT_EQ(ERR_IO_PENDING, |
| 396 req.handle.Init("a", "www.google.com", 80, 5, &req)); |
| 397 |
| 398 // There is a benign race condition here. The worker pool may or may not post |
| 399 // the tasks before we get here. It won't test the case properly if it |
| 400 // doesn't, but 100ms should be enough most of the time. |
| 401 |
| 402 // Let the first ConnectingSocket for the handle run. This should have been |
| 403 // canceled, so it shouldn't update the state of any Request. |
| 404 PlatformThread::Sleep(100); |
| 405 MessageLoop::current()->RunAllPending(); |
| 406 |
| 407 // Let the second ConnectingSocket for the handle run. If the first |
| 408 // ConnectingSocket updated the state of any request, this will crash. |
| 409 PlatformThread::Sleep(100); |
| 410 MessageLoop::current()->RunAllPending(); |
| 411 |
| 412 req.handle.Reset(); |
| 413 // The handle's Reset method may have posted a task. |
| 414 MessageLoop::current()->RunAllPending(); |
| 229 } | 415 } |
| 230 | 416 |
| 231 TEST_F(ClientSocketPoolTest, CancelRequest) { | 417 TEST_F(ClientSocketPoolTest, CancelRequest) { |
| 232 int rv; | 418 scoped_ptr<TestSocketRequest> reqs[kNumRequests]; |
| 233 | |
| 234 scoped_ptr<TestSocketRequest> reqs[kMaxSocketsPerGroup + kNumPendingRequests]; | |
| 235 | 419 |
| 236 for (size_t i = 0; i < arraysize(reqs); ++i) | 420 for (size_t i = 0; i < arraysize(reqs); ++i) |
| 237 reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_)); | 421 reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_)); |
| 238 | 422 |
| 239 // Create connections or queue up requests. | 423 // Create connections or queue up requests. |
| 240 for (int i = 0; i < kMaxSocketsPerGroup; ++i) { | 424 for (int i = 0; i < kMaxSocketsPerGroup; ++i) { |
| 241 rv = reqs[i]->handle.Init("a", 5, reqs[i].get()); | 425 int rv = reqs[i]->handle.Init("a", "www.google.com", 80, 5, reqs[i].get()); |
| 242 EXPECT_EQ(net::OK, rv); | 426 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 243 reqs[i]->EnsureSocket(); | 427 EXPECT_EQ(OK, reqs[i]->WaitForResult()); |
| 244 } | 428 } |
| 429 |
| 245 for (int i = 0; i < kNumPendingRequests; ++i) { | 430 for (int i = 0; i < kNumPendingRequests; ++i) { |
| 246 rv = reqs[kMaxSocketsPerGroup + i]->handle.Init( | 431 int rv = reqs[kMaxSocketsPerGroup + i]->handle.Init( |
| 247 "a", kPriorities[i], reqs[kMaxSocketsPerGroup + i].get()); | 432 "a", "www.google.com", 80, kPriorities[i], |
| 248 EXPECT_EQ(net::ERR_IO_PENDING, rv); | 433 reqs[kMaxSocketsPerGroup + i].get()); |
| 434 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 249 } | 435 } |
| 250 | 436 |
| 251 // Cancel a request. | 437 // Cancel a request. |
| 252 size_t index_to_cancel = kMaxSocketsPerGroup + 2; | 438 size_t index_to_cancel = kMaxSocketsPerGroup + 2; |
| 253 EXPECT_TRUE(!reqs[index_to_cancel]->handle.is_initialized()); | 439 EXPECT_TRUE(!reqs[index_to_cancel]->handle.is_initialized()); |
| 254 reqs[index_to_cancel]->handle.Reset(); | 440 reqs[index_to_cancel]->handle.Reset(); |
| 255 | 441 |
| 256 // Release any connections until we have no connections. | 442 // Release any connections until we have no connections. |
| 257 bool released_one; | 443 bool released_one; |
| 258 do { | 444 do { |
| 259 released_one = false; | 445 released_one = false; |
| 260 for (size_t i = 0; i < arraysize(reqs); ++i) { | 446 for (size_t i = 0; i < arraysize(reqs); ++i) { |
| 261 if (reqs[i]->handle.is_initialized()) { | 447 if (reqs[i]->handle.is_initialized()) { |
| 262 reqs[i]->handle.Reset(); | 448 reqs[i]->handle.Reset(); |
| 263 MessageLoop::current()->RunAllPending(); | 449 MessageLoop::current()->RunAllPending(); |
| 264 released_one = true; | 450 released_one = true; |
| 265 } | 451 } |
| 266 } | 452 } |
| 267 } while (released_one); | 453 } while (released_one); |
| 268 | 454 |
| 269 EXPECT_EQ(kMaxSocketsPerGroup, MockClientSocket::allocation_count); | 455 EXPECT_EQ(kMaxSocketsPerGroup, client_socket_factory_.allocation_count()); |
| 270 EXPECT_EQ(kNumPendingRequests - 1, TestSocketRequest::completion_count); | 456 EXPECT_EQ(kNumRequests - 1, TestSocketRequest::completion_count); |
| 271 for (int i = 0; i < kMaxSocketsPerGroup; ++i) { | 457 for (int i = 0; i < kMaxSocketsPerGroup; ++i) { |
| 272 EXPECT_EQ(request_order_[i], reqs[i].get()) << | 458 EXPECT_EQ(request_order_[i], reqs[i].get()) << |
| 273 "Request " << i << " was not in order."; | 459 "Request " << i << " was not in order."; |
| 274 } | 460 } |
| 275 | 461 |
| 276 for (int i = 0; i < kNumPendingRequests - 1; ++i) { | 462 for (int i = 0; i < kNumPendingRequests - 1; ++i) { |
| 277 if (i == 2) continue; | 463 if (i == 2) continue; |
| 278 int index_in_queue = (kNumPendingRequests - 1) - kPriorities[i]; | 464 int index_in_queue = (kNumPendingRequests - 1) - kPriorities[i]; |
| 279 if (kPriorities[i] < kPriorities[index_to_cancel - kMaxSocketsPerGroup]) | 465 if (kPriorities[i] < kPriorities[index_to_cancel - kMaxSocketsPerGroup]) |
| 280 index_in_queue--; | 466 index_in_queue--; |
| 281 EXPECT_EQ(request_order_[kMaxSocketsPerGroup + index_in_queue], | 467 EXPECT_EQ(request_order_[kMaxSocketsPerGroup + index_in_queue], |
| 282 reqs[kMaxSocketsPerGroup + i].get()) << | 468 reqs[kMaxSocketsPerGroup + i].get()) << |
| 283 "Request " << kMaxSocketsPerGroup + i << " was not in order."; | 469 "Request " << kMaxSocketsPerGroup + i << " was not in order."; |
| 284 } | 470 } |
| 285 | 471 |
| 286 EXPECT_EQ(request_order_[arraysize(reqs) - 2], | 472 EXPECT_EQ(request_order_[arraysize(reqs) - 2], |
| 287 reqs[arraysize(reqs) - 1].get()) << | 473 reqs[arraysize(reqs) - 1].get()) << |
| 288 "The last request with priority 1 should not have been inserted " | 474 "The last request with priority 1 should not have been inserted " |
| 289 "earlier into the queue."; | 475 "earlier into the queue."; |
| 290 } | 476 } |
| 291 | 477 |
| 292 } // namespace | 478 } // namespace |
| 479 |
| 480 } // namespace net |
| OLD | NEW |