Make mojo message building and validation follow the depth-first traversal order.
[chromium-blink-merge.git] / net / spdy / spdy_session_pool_unittest.cc
blob58002dcdea2f199779abe21ebe9ca6405051446d
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, kProtoSPDY4));
56 // A delegate that opens a new session when it is closed.
57 class SessionOpeningDelegate : public SpdyStream::Delegate {
58 public:
59 SessionOpeningDelegate(SpdySessionPool* spdy_session_pool,
60 const SpdySessionKey& key)
61 : spdy_session_pool_(spdy_session_pool),
62 key_(key) {}
64 virtual ~SessionOpeningDelegate() {}
66 virtual void OnRequestHeadersSent() OVERRIDE {}
68 virtual SpdyResponseHeadersStatus OnResponseHeadersUpdated(
69 const SpdyHeaderBlock& response_headers) OVERRIDE {
70 return RESPONSE_HEADERS_ARE_COMPLETE;
73 virtual void OnDataReceived(scoped_ptr<SpdyBuffer> buffer) OVERRIDE {}
75 virtual void OnDataSent() OVERRIDE {}
77 virtual void OnClose(int status) OVERRIDE {
78 ignore_result(CreateFakeSpdySession(spdy_session_pool_, key_));
81 private:
82 SpdySessionPool* const spdy_session_pool_;
83 const SpdySessionKey key_;
86 // Set up a SpdyStream to create a new session when it is closed.
87 // CloseCurrentSessions should not close the newly-created session.
88 TEST_P(SpdySessionPoolTest, CloseCurrentSessions) {
89 const char kTestHost[] = "www.foo.com";
90 const int kTestPort = 80;
92 session_deps_.host_resolver->set_synchronous_mode(true);
94 HostPortPair test_host_port_pair(kTestHost, kTestPort);
95 SpdySessionKey test_key =
96 SpdySessionKey(
97 test_host_port_pair, ProxyServer::Direct(),
98 PRIVACY_MODE_DISABLED);
100 MockConnect connect_data(SYNCHRONOUS, OK);
101 MockRead reads[] = {
102 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
105 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
106 data.set_connect_data(connect_data);
107 session_deps_.socket_factory->AddSocketDataProvider(&data);
109 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
110 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
112 CreateNetworkSession();
114 // Setup the first session to the first host.
115 base::WeakPtr<SpdySession> session =
116 CreateInsecureSpdySession(http_session_, test_key, BoundNetLog());
118 // Flush the SpdySession::OnReadComplete() task.
119 base::MessageLoop::current()->RunUntilIdle();
121 // Verify that we have sessions for everything.
122 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
124 // Set the stream to create a new session when it is closed.
125 base::WeakPtr<SpdyStream> spdy_stream =
126 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
127 session, GURL("http://www.foo.com"),
128 MEDIUM, BoundNetLog());
129 SessionOpeningDelegate delegate(spdy_session_pool_, test_key);
130 spdy_stream->SetDelegate(&delegate);
132 // Close the current session.
133 spdy_session_pool_->CloseCurrentSessions(net::ERR_ABORTED);
135 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
138 TEST_P(SpdySessionPoolTest, CloseCurrentIdleSessions) {
139 MockConnect connect_data(SYNCHRONOUS, OK);
140 MockRead reads[] = {
141 MockRead(ASYNC, 0, 0) // EOF
144 session_deps_.host_resolver->set_synchronous_mode(true);
146 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
147 data.set_connect_data(connect_data);
148 session_deps_.socket_factory->AddSocketDataProvider(&data);
150 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
151 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
153 CreateNetworkSession();
155 // Set up session 1
156 const std::string kTestHost1("http://www.a.com");
157 HostPortPair test_host_port_pair1(kTestHost1, 80);
158 SpdySessionKey key1(test_host_port_pair1, ProxyServer::Direct(),
159 PRIVACY_MODE_DISABLED);
160 base::WeakPtr<SpdySession> session1 =
161 CreateInsecureSpdySession(http_session_, key1, BoundNetLog());
162 GURL url1(kTestHost1);
163 base::WeakPtr<SpdyStream> spdy_stream1 =
164 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
165 session1, url1, MEDIUM, BoundNetLog());
166 ASSERT_TRUE(spdy_stream1.get() != NULL);
168 // Set up session 2
169 session_deps_.socket_factory->AddSocketDataProvider(&data);
170 const std::string kTestHost2("http://www.b.com");
171 HostPortPair test_host_port_pair2(kTestHost2, 80);
172 SpdySessionKey key2(test_host_port_pair2, ProxyServer::Direct(),
173 PRIVACY_MODE_DISABLED);
174 base::WeakPtr<SpdySession> session2 =
175 CreateInsecureSpdySession(http_session_, key2, BoundNetLog());
176 GURL url2(kTestHost2);
177 base::WeakPtr<SpdyStream> spdy_stream2 =
178 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
179 session2, url2, MEDIUM, BoundNetLog());
180 ASSERT_TRUE(spdy_stream2.get() != NULL);
182 // Set up session 3
183 session_deps_.socket_factory->AddSocketDataProvider(&data);
184 const std::string kTestHost3("http://www.c.com");
185 HostPortPair test_host_port_pair3(kTestHost3, 80);
186 SpdySessionKey key3(test_host_port_pair3, ProxyServer::Direct(),
187 PRIVACY_MODE_DISABLED);
188 base::WeakPtr<SpdySession> session3 =
189 CreateInsecureSpdySession(http_session_, key3, BoundNetLog());
190 GURL url3(kTestHost3);
191 base::WeakPtr<SpdyStream> spdy_stream3 =
192 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
193 session3, url3, MEDIUM, BoundNetLog());
194 ASSERT_TRUE(spdy_stream3.get() != NULL);
196 // All sessions are active and not closed
197 EXPECT_TRUE(session1->is_active());
198 EXPECT_FALSE(session1->IsClosed());
199 EXPECT_TRUE(session2->is_active());
200 EXPECT_FALSE(session2->IsClosed());
201 EXPECT_TRUE(session3->is_active());
202 EXPECT_FALSE(session3->IsClosed());
204 // Should not do anything, all are active
205 spdy_session_pool_->CloseCurrentIdleSessions();
206 EXPECT_TRUE(session1->is_active());
207 EXPECT_FALSE(session1->IsClosed());
208 EXPECT_TRUE(session2->is_active());
209 EXPECT_FALSE(session2->IsClosed());
210 EXPECT_TRUE(session3->is_active());
211 EXPECT_FALSE(session3->IsClosed());
213 // Make sessions 1 and 3 inactive, but keep them open.
214 // Session 2 still open and active
215 session1->CloseCreatedStream(spdy_stream1, OK);
216 EXPECT_EQ(NULL, spdy_stream1.get());
217 session3->CloseCreatedStream(spdy_stream3, OK);
218 EXPECT_EQ(NULL, spdy_stream3.get());
219 EXPECT_FALSE(session1->is_active());
220 EXPECT_FALSE(session1->IsClosed());
221 EXPECT_TRUE(session2->is_active());
222 EXPECT_FALSE(session2->IsClosed());
223 EXPECT_FALSE(session3->is_active());
224 EXPECT_FALSE(session3->IsClosed());
226 // Should close session 1 and 3, 2 should be left open
227 spdy_session_pool_->CloseCurrentIdleSessions();
228 EXPECT_TRUE(session1 == NULL);
229 EXPECT_TRUE(session2->is_active());
230 EXPECT_FALSE(session2->IsClosed());
231 EXPECT_TRUE(session3 == NULL);
233 // Should not do anything
234 spdy_session_pool_->CloseCurrentIdleSessions();
235 EXPECT_TRUE(session2->is_active());
236 EXPECT_FALSE(session2->IsClosed());
238 // Make 2 not active
239 session2->CloseCreatedStream(spdy_stream2, OK);
240 EXPECT_EQ(NULL, spdy_stream2.get());
241 EXPECT_FALSE(session2->is_active());
242 EXPECT_FALSE(session2->IsClosed());
244 // This should close session 2
245 spdy_session_pool_->CloseCurrentIdleSessions();
246 EXPECT_TRUE(session2 == NULL);
249 // Set up a SpdyStream to create a new session when it is closed.
250 // CloseAllSessions should close the newly-created session.
251 TEST_P(SpdySessionPoolTest, CloseAllSessions) {
252 const char kTestHost[] = "www.foo.com";
253 const int kTestPort = 80;
255 session_deps_.host_resolver->set_synchronous_mode(true);
257 HostPortPair test_host_port_pair(kTestHost, kTestPort);
258 SpdySessionKey test_key =
259 SpdySessionKey(
260 test_host_port_pair, ProxyServer::Direct(),
261 PRIVACY_MODE_DISABLED);
263 MockConnect connect_data(SYNCHRONOUS, OK);
264 MockRead reads[] = {
265 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
268 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
269 data.set_connect_data(connect_data);
270 session_deps_.socket_factory->AddSocketDataProvider(&data);
272 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
273 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
275 CreateNetworkSession();
277 // Setup the first session to the first host.
278 base::WeakPtr<SpdySession> session =
279 CreateInsecureSpdySession(http_session_, test_key, BoundNetLog());
281 // Flush the SpdySession::OnReadComplete() task.
282 base::MessageLoop::current()->RunUntilIdle();
284 // Verify that we have sessions for everything.
285 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
287 // Set the stream to create a new session when it is closed.
288 base::WeakPtr<SpdyStream> spdy_stream =
289 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
290 session, GURL("http://www.foo.com"),
291 MEDIUM, BoundNetLog());
292 SessionOpeningDelegate delegate(spdy_session_pool_, test_key);
293 spdy_stream->SetDelegate(&delegate);
295 // Close the current session.
296 spdy_session_pool_->CloseAllSessions();
298 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_key));
301 // This test has three variants, one for each style of closing the connection.
302 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_SESSIONS_MANUALLY,
303 // the sessions are closed manually, calling SpdySessionPool::Remove() directly.
304 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_CURRENT_SESSIONS,
305 // sessions are closed with SpdySessionPool::CloseCurrentSessions().
306 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_IDLE_SESSIONS,
307 // sessions are closed with SpdySessionPool::CloseIdleSessions().
308 void SpdySessionPoolTest::RunIPPoolingTest(
309 SpdyPoolCloseSessionsType close_sessions_type) {
310 const int kTestPort = 80;
311 struct TestHosts {
312 std::string url;
313 std::string name;
314 std::string iplist;
315 SpdySessionKey key;
316 AddressList addresses;
317 } test_hosts[] = {
318 { "http:://www.foo.com",
319 "www.foo.com",
320 "192.0.2.33,192.168.0.1,192.168.0.5"
322 { "http://js.foo.com",
323 "js.foo.com",
324 "192.168.0.2,192.168.0.3,192.168.0.5,192.0.2.33"
326 { "http://images.foo.com",
327 "images.foo.com",
328 "192.168.0.4,192.168.0.3"
332 session_deps_.host_resolver->set_synchronous_mode(true);
333 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_hosts); i++) {
334 session_deps_.host_resolver->rules()->AddIPLiteralRule(
335 test_hosts[i].name, test_hosts[i].iplist, std::string());
337 // This test requires that the HostResolver cache be populated. Normal
338 // code would have done this already, but we do it manually.
339 HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
340 session_deps_.host_resolver->Resolve(info,
341 DEFAULT_PRIORITY,
342 &test_hosts[i].addresses,
343 CompletionCallback(),
344 NULL,
345 BoundNetLog());
347 // Setup a SpdySessionKey
348 test_hosts[i].key = SpdySessionKey(
349 HostPortPair(test_hosts[i].name, kTestPort), ProxyServer::Direct(),
350 PRIVACY_MODE_DISABLED);
353 MockConnect connect_data(SYNCHRONOUS, OK);
354 MockRead reads[] = {
355 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
358 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
359 data.set_connect_data(connect_data);
360 session_deps_.socket_factory->AddSocketDataProvider(&data);
362 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
363 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
365 CreateNetworkSession();
367 // Setup the first session to the first host.
368 base::WeakPtr<SpdySession> session =
369 CreateInsecureSpdySession(
370 http_session_, test_hosts[0].key, BoundNetLog());
372 // Flush the SpdySession::OnReadComplete() task.
373 base::MessageLoop::current()->RunUntilIdle();
375 // The third host has no overlap with the first, so it can't pool IPs.
376 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
378 // The second host overlaps with the first, and should IP pool.
379 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
381 // Verify that the second host, through a proxy, won't share the IP.
382 SpdySessionKey proxy_key(test_hosts[1].key.host_port_pair(),
383 ProxyServer::FromPacString("HTTP http://proxy.foo.com/"),
384 PRIVACY_MODE_DISABLED);
385 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, proxy_key));
387 // Overlap between 2 and 3 does is not transitive to 1.
388 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
390 // Create a new session to host 2.
391 session_deps_.socket_factory->AddSocketDataProvider(&data);
392 base::WeakPtr<SpdySession> session2 =
393 CreateInsecureSpdySession(
394 http_session_, test_hosts[2].key, BoundNetLog());
396 // Verify that we have sessions for everything.
397 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[0].key));
398 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
399 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
401 // Grab the session to host 1 and verify that it is the same session
402 // we got with host 0, and that is a different from host 2's session.
403 base::WeakPtr<SpdySession> session1 =
404 spdy_session_pool_->FindAvailableSession(
405 test_hosts[1].key, BoundNetLog());
406 EXPECT_EQ(session.get(), session1.get());
407 EXPECT_NE(session2.get(), session1.get());
409 // Remove the aliases and observe that we still have a session for host1.
410 SpdySessionPoolPeer pool_peer(spdy_session_pool_);
411 pool_peer.RemoveAliases(test_hosts[0].key);
412 pool_peer.RemoveAliases(test_hosts[1].key);
413 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
415 // Expire the host cache
416 session_deps_.host_resolver->GetHostCache()->clear();
417 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
419 // Cleanup the sessions.
420 switch (close_sessions_type) {
421 case SPDY_POOL_CLOSE_SESSIONS_MANUALLY:
422 session->CloseSessionOnError(ERR_ABORTED, std::string());
423 EXPECT_TRUE(session == NULL);
424 session2->CloseSessionOnError(ERR_ABORTED, std::string());
425 EXPECT_TRUE(session2 == NULL);
426 break;
427 case SPDY_POOL_CLOSE_CURRENT_SESSIONS:
428 spdy_session_pool_->CloseCurrentSessions(ERR_ABORTED);
429 break;
430 case SPDY_POOL_CLOSE_IDLE_SESSIONS:
431 GURL url(test_hosts[0].url);
432 base::WeakPtr<SpdyStream> spdy_stream =
433 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
434 session, url, MEDIUM, BoundNetLog());
435 GURL url1(test_hosts[1].url);
436 base::WeakPtr<SpdyStream> spdy_stream1 =
437 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
438 session1, url1, MEDIUM, BoundNetLog());
439 GURL url2(test_hosts[2].url);
440 base::WeakPtr<SpdyStream> spdy_stream2 =
441 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
442 session2, url2, MEDIUM, BoundNetLog());
444 // Close streams to make spdy_session and spdy_session1 inactive.
445 session->CloseCreatedStream(spdy_stream, OK);
446 EXPECT_EQ(NULL, spdy_stream.get());
447 session1->CloseCreatedStream(spdy_stream1, OK);
448 EXPECT_EQ(NULL, spdy_stream1.get());
450 // Check spdy_session and spdy_session1 are not closed.
451 EXPECT_FALSE(session->is_active());
452 EXPECT_FALSE(session->IsClosed());
453 EXPECT_FALSE(session1->is_active());
454 EXPECT_FALSE(session1->IsClosed());
455 EXPECT_TRUE(session2->is_active());
456 EXPECT_FALSE(session2->IsClosed());
458 // Test that calling CloseIdleSessions, does not cause a crash.
459 // http://crbug.com/181400
460 spdy_session_pool_->CloseCurrentIdleSessions();
462 // Verify spdy_session and spdy_session1 are closed.
463 EXPECT_TRUE(session == NULL);
464 EXPECT_TRUE(session1 == NULL);
465 EXPECT_TRUE(session2->is_active());
466 EXPECT_FALSE(session2->IsClosed());
468 spdy_stream2->Cancel();
469 EXPECT_EQ(NULL, spdy_stream.get());
470 EXPECT_EQ(NULL, spdy_stream1.get());
471 EXPECT_EQ(NULL, spdy_stream2.get());
472 session2->CloseSessionOnError(ERR_ABORTED, std::string());
473 EXPECT_TRUE(session2 == NULL);
474 break;
477 // Verify that the map is all cleaned up.
478 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[0].key));
479 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
480 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
483 TEST_P(SpdySessionPoolTest, IPPooling) {
484 RunIPPoolingTest(SPDY_POOL_CLOSE_SESSIONS_MANUALLY);
487 TEST_P(SpdySessionPoolTest, IPPoolingCloseCurrentSessions) {
488 RunIPPoolingTest(SPDY_POOL_CLOSE_CURRENT_SESSIONS);
491 TEST_P(SpdySessionPoolTest, IPPoolingCloseIdleSessions) {
492 RunIPPoolingTest(SPDY_POOL_CLOSE_IDLE_SESSIONS);
495 } // namespace
497 } // namespace net