Revert of Update WV test license server config to use portable sdk server. (https...
[chromium-blink-merge.git] / net / spdy / spdy_session_pool_unittest.cc
blobc9873fc8141d3b830a263339f697c3391ab6f655
1 // Copyright (c) 2013 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.
5 #include "net/spdy/spdy_session_pool.h"
7 #include <cstddef>
8 #include <string>
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "net/dns/host_cache.h"
13 #include "net/http/http_network_session.h"
14 #include "net/socket/client_socket_handle.h"
15 #include "net/socket/transport_client_socket_pool.h"
16 #include "net/spdy/spdy_session.h"
17 #include "net/spdy/spdy_test_util_common.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 namespace net {
22 namespace {
24 class SpdySessionPoolTest : public ::testing::Test,
25 public ::testing::WithParamInterface<NextProto> {
26 protected:
27 // Used by RunIPPoolingTest().
28 enum SpdyPoolCloseSessionsType {
29 SPDY_POOL_CLOSE_SESSIONS_MANUALLY,
30 SPDY_POOL_CLOSE_CURRENT_SESSIONS,
31 SPDY_POOL_CLOSE_IDLE_SESSIONS,
34 SpdySessionPoolTest()
35 : session_deps_(GetParam()),
36 spdy_session_pool_(NULL) {}
38 void CreateNetworkSession() {
39 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
40 spdy_session_pool_ = http_session_->spdy_session_pool();
43 void RunIPPoolingTest(SpdyPoolCloseSessionsType close_sessions_type);
45 SpdySessionDependencies session_deps_;
46 scoped_refptr<HttpNetworkSession> http_session_;
47 SpdySessionPool* spdy_session_pool_;
50 INSTANTIATE_TEST_CASE_P(
51 NextProto,
52 SpdySessionPoolTest,
53 testing::Values(kProtoDeprecatedSPDY2,
54 kProtoSPDY3, kProtoSPDY31, kProtoSPDY4a2,
55 kProtoHTTP2Draft04));
57 // A delegate that opens a new session when it is closed.
58 class SessionOpeningDelegate : public SpdyStream::Delegate {
59 public:
60 SessionOpeningDelegate(SpdySessionPool* spdy_session_pool,
61 const SpdySessionKey& key)
62 : spdy_session_pool_(spdy_session_pool),
63 key_(key) {}
65 virtual ~SessionOpeningDelegate() {}
67 virtual void OnRequestHeadersSent() OVERRIDE {}
69 virtual SpdyResponseHeadersStatus OnResponseHeadersUpdated(
70 const SpdyHeaderBlock& response_headers) OVERRIDE {
71 return RESPONSE_HEADERS_ARE_COMPLETE;
74 virtual void OnDataReceived(scoped_ptr<SpdyBuffer> buffer) OVERRIDE {}
76 virtual void OnDataSent() OVERRIDE {}
78 virtual void OnClose(int status) OVERRIDE {
79 ignore_result(CreateFakeSpdySession(spdy_session_pool_, key_));
82 private:
83 SpdySessionPool* const spdy_session_pool_;
84 const SpdySessionKey key_;
87 // Set up a SpdyStream to create a new session when it is closed.
88 // CloseCurrentSessions should not close the newly-created session.
89 TEST_P(SpdySessionPoolTest, CloseCurrentSessions) {
90 const char kTestHost[] = "www.foo.com";
91 const int kTestPort = 80;
93 session_deps_.host_resolver->set_synchronous_mode(true);
95 HostPortPair test_host_port_pair(kTestHost, kTestPort);
96 SpdySessionKey test_key =
97 SpdySessionKey(
98 test_host_port_pair, ProxyServer::Direct(),
99 kPrivacyModeDisabled);
101 MockConnect connect_data(SYNCHRONOUS, OK);
102 MockRead reads[] = {
103 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
106 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
107 data.set_connect_data(connect_data);
108 session_deps_.socket_factory->AddSocketDataProvider(&data);
110 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
111 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
113 CreateNetworkSession();
115 // Setup the first session to the first host.
116 base::WeakPtr<SpdySession> session =
117 CreateInsecureSpdySession(http_session_, test_key, BoundNetLog());
119 // Flush the SpdySession::OnReadComplete() task.
120 base::MessageLoop::current()->RunUntilIdle();
122 // Verify that we have sessions for everything.
123 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
125 // Set the stream to create a new session when it is closed.
126 base::WeakPtr<SpdyStream> spdy_stream =
127 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
128 session, GURL("http://www.foo.com"),
129 MEDIUM, BoundNetLog());
130 SessionOpeningDelegate delegate(spdy_session_pool_, test_key);
131 spdy_stream->SetDelegate(&delegate);
133 // Close the current session.
134 spdy_session_pool_->CloseCurrentSessions(net::ERR_ABORTED);
136 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
139 TEST_P(SpdySessionPoolTest, CloseCurrentIdleSessions) {
140 MockConnect connect_data(SYNCHRONOUS, OK);
141 MockRead reads[] = {
142 MockRead(ASYNC, 0, 0) // EOF
145 session_deps_.host_resolver->set_synchronous_mode(true);
147 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
148 data.set_connect_data(connect_data);
149 session_deps_.socket_factory->AddSocketDataProvider(&data);
151 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
152 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
154 CreateNetworkSession();
156 // Set up session 1
157 const std::string kTestHost1("http://www.a.com");
158 HostPortPair test_host_port_pair1(kTestHost1, 80);
159 SpdySessionKey key1(test_host_port_pair1, ProxyServer::Direct(),
160 kPrivacyModeDisabled);
161 base::WeakPtr<SpdySession> session1 =
162 CreateInsecureSpdySession(http_session_, key1, BoundNetLog());
163 GURL url1(kTestHost1);
164 base::WeakPtr<SpdyStream> spdy_stream1 =
165 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
166 session1, url1, MEDIUM, BoundNetLog());
167 ASSERT_TRUE(spdy_stream1.get() != NULL);
169 // Set up session 2
170 session_deps_.socket_factory->AddSocketDataProvider(&data);
171 const std::string kTestHost2("http://www.b.com");
172 HostPortPair test_host_port_pair2(kTestHost2, 80);
173 SpdySessionKey key2(test_host_port_pair2, ProxyServer::Direct(),
174 kPrivacyModeDisabled);
175 base::WeakPtr<SpdySession> session2 =
176 CreateInsecureSpdySession(http_session_, key2, BoundNetLog());
177 GURL url2(kTestHost2);
178 base::WeakPtr<SpdyStream> spdy_stream2 =
179 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
180 session2, url2, MEDIUM, BoundNetLog());
181 ASSERT_TRUE(spdy_stream2.get() != NULL);
183 // Set up session 3
184 session_deps_.socket_factory->AddSocketDataProvider(&data);
185 const std::string kTestHost3("http://www.c.com");
186 HostPortPair test_host_port_pair3(kTestHost3, 80);
187 SpdySessionKey key3(test_host_port_pair3, ProxyServer::Direct(),
188 kPrivacyModeDisabled);
189 base::WeakPtr<SpdySession> session3 =
190 CreateInsecureSpdySession(http_session_, key3, BoundNetLog());
191 GURL url3(kTestHost3);
192 base::WeakPtr<SpdyStream> spdy_stream3 =
193 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
194 session3, url3, MEDIUM, BoundNetLog());
195 ASSERT_TRUE(spdy_stream3.get() != NULL);
197 // All sessions are active and not closed
198 EXPECT_TRUE(session1->is_active());
199 EXPECT_FALSE(session1->IsClosed());
200 EXPECT_TRUE(session2->is_active());
201 EXPECT_FALSE(session2->IsClosed());
202 EXPECT_TRUE(session3->is_active());
203 EXPECT_FALSE(session3->IsClosed());
205 // Should not do anything, all are active
206 spdy_session_pool_->CloseCurrentIdleSessions();
207 EXPECT_TRUE(session1->is_active());
208 EXPECT_FALSE(session1->IsClosed());
209 EXPECT_TRUE(session2->is_active());
210 EXPECT_FALSE(session2->IsClosed());
211 EXPECT_TRUE(session3->is_active());
212 EXPECT_FALSE(session3->IsClosed());
214 // Make sessions 1 and 3 inactive, but keep them open.
215 // Session 2 still open and active
216 session1->CloseCreatedStream(spdy_stream1, OK);
217 EXPECT_EQ(NULL, spdy_stream1.get());
218 session3->CloseCreatedStream(spdy_stream3, OK);
219 EXPECT_EQ(NULL, spdy_stream3.get());
220 EXPECT_FALSE(session1->is_active());
221 EXPECT_FALSE(session1->IsClosed());
222 EXPECT_TRUE(session2->is_active());
223 EXPECT_FALSE(session2->IsClosed());
224 EXPECT_FALSE(session3->is_active());
225 EXPECT_FALSE(session3->IsClosed());
227 // Should close session 1 and 3, 2 should be left open
228 spdy_session_pool_->CloseCurrentIdleSessions();
229 EXPECT_TRUE(session1 == NULL);
230 EXPECT_TRUE(session2->is_active());
231 EXPECT_FALSE(session2->IsClosed());
232 EXPECT_TRUE(session3 == NULL);
234 // Should not do anything
235 spdy_session_pool_->CloseCurrentIdleSessions();
236 EXPECT_TRUE(session2->is_active());
237 EXPECT_FALSE(session2->IsClosed());
239 // Make 2 not active
240 session2->CloseCreatedStream(spdy_stream2, OK);
241 EXPECT_EQ(NULL, spdy_stream2.get());
242 EXPECT_FALSE(session2->is_active());
243 EXPECT_FALSE(session2->IsClosed());
245 // This should close session 2
246 spdy_session_pool_->CloseCurrentIdleSessions();
247 EXPECT_TRUE(session2 == NULL);
250 // Set up a SpdyStream to create a new session when it is closed.
251 // CloseAllSessions should close the newly-created session.
252 TEST_P(SpdySessionPoolTest, CloseAllSessions) {
253 const char kTestHost[] = "www.foo.com";
254 const int kTestPort = 80;
256 session_deps_.host_resolver->set_synchronous_mode(true);
258 HostPortPair test_host_port_pair(kTestHost, kTestPort);
259 SpdySessionKey test_key =
260 SpdySessionKey(
261 test_host_port_pair, ProxyServer::Direct(),
262 kPrivacyModeDisabled);
264 MockConnect connect_data(SYNCHRONOUS, OK);
265 MockRead reads[] = {
266 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
269 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
270 data.set_connect_data(connect_data);
271 session_deps_.socket_factory->AddSocketDataProvider(&data);
273 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
274 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
276 CreateNetworkSession();
278 // Setup the first session to the first host.
279 base::WeakPtr<SpdySession> session =
280 CreateInsecureSpdySession(http_session_, test_key, BoundNetLog());
282 // Flush the SpdySession::OnReadComplete() task.
283 base::MessageLoop::current()->RunUntilIdle();
285 // Verify that we have sessions for everything.
286 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
288 // Set the stream to create a new session when it is closed.
289 base::WeakPtr<SpdyStream> spdy_stream =
290 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
291 session, GURL("http://www.foo.com"),
292 MEDIUM, BoundNetLog());
293 SessionOpeningDelegate delegate(spdy_session_pool_, test_key);
294 spdy_stream->SetDelegate(&delegate);
296 // Close the current session.
297 spdy_session_pool_->CloseAllSessions();
299 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_key));
302 // This test has three variants, one for each style of closing the connection.
303 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_SESSIONS_MANUALLY,
304 // the sessions are closed manually, calling SpdySessionPool::Remove() directly.
305 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_CURRENT_SESSIONS,
306 // sessions are closed with SpdySessionPool::CloseCurrentSessions().
307 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_IDLE_SESSIONS,
308 // sessions are closed with SpdySessionPool::CloseIdleSessions().
309 void SpdySessionPoolTest::RunIPPoolingTest(
310 SpdyPoolCloseSessionsType close_sessions_type) {
311 const int kTestPort = 80;
312 struct TestHosts {
313 std::string url;
314 std::string name;
315 std::string iplist;
316 SpdySessionKey key;
317 AddressList addresses;
318 } test_hosts[] = {
319 { "http:://www.foo.com",
320 "www.foo.com",
321 "192.0.2.33,192.168.0.1,192.168.0.5"
323 { "http://js.foo.com",
324 "js.foo.com",
325 "192.168.0.2,192.168.0.3,192.168.0.5,192.0.2.33"
327 { "http://images.foo.com",
328 "images.foo.com",
329 "192.168.0.4,192.168.0.3"
333 session_deps_.host_resolver->set_synchronous_mode(true);
334 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_hosts); i++) {
335 session_deps_.host_resolver->rules()->AddIPLiteralRule(
336 test_hosts[i].name, test_hosts[i].iplist, std::string());
338 // This test requires that the HostResolver cache be populated. Normal
339 // code would have done this already, but we do it manually.
340 HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
341 session_deps_.host_resolver->Resolve(info,
342 DEFAULT_PRIORITY,
343 &test_hosts[i].addresses,
344 CompletionCallback(),
345 NULL,
346 BoundNetLog());
348 // Setup a SpdySessionKey
349 test_hosts[i].key = SpdySessionKey(
350 HostPortPair(test_hosts[i].name, kTestPort), ProxyServer::Direct(),
351 kPrivacyModeDisabled);
354 MockConnect connect_data(SYNCHRONOUS, OK);
355 MockRead reads[] = {
356 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
359 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
360 data.set_connect_data(connect_data);
361 session_deps_.socket_factory->AddSocketDataProvider(&data);
363 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
364 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
366 CreateNetworkSession();
368 // Setup the first session to the first host.
369 base::WeakPtr<SpdySession> session =
370 CreateInsecureSpdySession(
371 http_session_, test_hosts[0].key, BoundNetLog());
373 // Flush the SpdySession::OnReadComplete() task.
374 base::MessageLoop::current()->RunUntilIdle();
376 // The third host has no overlap with the first, so it can't pool IPs.
377 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
379 // The second host overlaps with the first, and should IP pool.
380 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
382 // Verify that the second host, through a proxy, won't share the IP.
383 SpdySessionKey proxy_key(test_hosts[1].key.host_port_pair(),
384 ProxyServer::FromPacString("HTTP http://proxy.foo.com/"),
385 kPrivacyModeDisabled);
386 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, proxy_key));
388 // Overlap between 2 and 3 does is not transitive to 1.
389 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
391 // Create a new session to host 2.
392 session_deps_.socket_factory->AddSocketDataProvider(&data);
393 base::WeakPtr<SpdySession> session2 =
394 CreateInsecureSpdySession(
395 http_session_, test_hosts[2].key, BoundNetLog());
397 // Verify that we have sessions for everything.
398 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[0].key));
399 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
400 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
402 // Grab the session to host 1 and verify that it is the same session
403 // we got with host 0, and that is a different from host 2's session.
404 base::WeakPtr<SpdySession> session1 =
405 spdy_session_pool_->FindAvailableSession(
406 test_hosts[1].key, BoundNetLog());
407 EXPECT_EQ(session.get(), session1.get());
408 EXPECT_NE(session2.get(), session1.get());
410 // Remove the aliases and observe that we still have a session for host1.
411 SpdySessionPoolPeer pool_peer(spdy_session_pool_);
412 pool_peer.RemoveAliases(test_hosts[0].key);
413 pool_peer.RemoveAliases(test_hosts[1].key);
414 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
416 // Expire the host cache
417 session_deps_.host_resolver->GetHostCache()->clear();
418 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
420 // Cleanup the sessions.
421 switch (close_sessions_type) {
422 case SPDY_POOL_CLOSE_SESSIONS_MANUALLY:
423 session->CloseSessionOnError(ERR_ABORTED, std::string());
424 EXPECT_TRUE(session == NULL);
425 session2->CloseSessionOnError(ERR_ABORTED, std::string());
426 EXPECT_TRUE(session2 == NULL);
427 break;
428 case SPDY_POOL_CLOSE_CURRENT_SESSIONS:
429 spdy_session_pool_->CloseCurrentSessions(ERR_ABORTED);
430 break;
431 case SPDY_POOL_CLOSE_IDLE_SESSIONS:
432 GURL url(test_hosts[0].url);
433 base::WeakPtr<SpdyStream> spdy_stream =
434 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
435 session, url, MEDIUM, BoundNetLog());
436 GURL url1(test_hosts[1].url);
437 base::WeakPtr<SpdyStream> spdy_stream1 =
438 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
439 session1, url1, MEDIUM, BoundNetLog());
440 GURL url2(test_hosts[2].url);
441 base::WeakPtr<SpdyStream> spdy_stream2 =
442 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
443 session2, url2, MEDIUM, BoundNetLog());
445 // Close streams to make spdy_session and spdy_session1 inactive.
446 session->CloseCreatedStream(spdy_stream, OK);
447 EXPECT_EQ(NULL, spdy_stream.get());
448 session1->CloseCreatedStream(spdy_stream1, OK);
449 EXPECT_EQ(NULL, spdy_stream1.get());
451 // Check spdy_session and spdy_session1 are not closed.
452 EXPECT_FALSE(session->is_active());
453 EXPECT_FALSE(session->IsClosed());
454 EXPECT_FALSE(session1->is_active());
455 EXPECT_FALSE(session1->IsClosed());
456 EXPECT_TRUE(session2->is_active());
457 EXPECT_FALSE(session2->IsClosed());
459 // Test that calling CloseIdleSessions, does not cause a crash.
460 // http://crbug.com/181400
461 spdy_session_pool_->CloseCurrentIdleSessions();
463 // Verify spdy_session and spdy_session1 are closed.
464 EXPECT_TRUE(session == NULL);
465 EXPECT_TRUE(session1 == NULL);
466 EXPECT_TRUE(session2->is_active());
467 EXPECT_FALSE(session2->IsClosed());
469 spdy_stream2->Cancel();
470 EXPECT_EQ(NULL, spdy_stream.get());
471 EXPECT_EQ(NULL, spdy_stream1.get());
472 EXPECT_EQ(NULL, spdy_stream2.get());
473 session2->CloseSessionOnError(ERR_ABORTED, std::string());
474 EXPECT_TRUE(session2 == NULL);
475 break;
478 // Verify that the map is all cleaned up.
479 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[0].key));
480 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
481 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
484 TEST_P(SpdySessionPoolTest, IPPooling) {
485 RunIPPoolingTest(SPDY_POOL_CLOSE_SESSIONS_MANUALLY);
488 TEST_P(SpdySessionPoolTest, IPPoolingCloseCurrentSessions) {
489 RunIPPoolingTest(SPDY_POOL_CLOSE_CURRENT_SESSIONS);
492 TEST_P(SpdySessionPoolTest, IPPoolingCloseIdleSessions) {
493 RunIPPoolingTest(SPDY_POOL_CLOSE_IDLE_SESSIONS);
496 } // namespace
498 } // namespace net