| Index: net/spdy/spdy_session_spdy2_unittest.cc
|
| diff --git a/net/spdy/spdy_session_spdy2_unittest.cc b/net/spdy/spdy_session_spdy2_unittest.cc
|
| index 3fde2b46dc5f192cc00daf8b62cc4f7519f581d9..6d56d6b4731a4a59652393b9540a75e6e13a9fbd 100644
|
| --- a/net/spdy/spdy_session_spdy2_unittest.cc
|
| +++ b/net/spdy/spdy_session_spdy2_unittest.cc
|
| @@ -1064,4 +1064,144 @@ TEST_F(SpdySessionSpdy2Test, CloseSessionOnError) {
|
| EXPECT_EQ(ERR_CONNECTION_CLOSED, request_params->status());
|
| }
|
|
|
| +TEST_F(SpdySessionSpdy2Test, CloseOneIdleConnection) {
|
| + MockHostResolver host_resolver;
|
| + CapturingBoundNetLog log(CapturingNetLog::kUnbounded);
|
| + ClientSocketPoolHistograms tcp_histograms("");
|
| + MockClientSocketFactory socket_factory;
|
| + MockConnect connect_data(SYNCHRONOUS, OK);
|
| + MockRead reads[] = {
|
| + MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
|
| + };
|
| + StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
|
| + data.set_connect_data(connect_data);
|
| + socket_factory.AddSocketDataProvider(&data);
|
| + socket_factory.AddSocketDataProvider(&data);
|
| + socket_factory.AddSocketDataProvider(&data);
|
| + socket_factory.AddSocketDataProvider(&data);
|
| + socket_factory.AddSocketDataProvider(&data);
|
| + socket_factory.AddSocketDataProvider(&data);
|
| + TransportClientSocketPool pool(
|
| + 3, 2,
|
| + &tcp_histograms,
|
| + &host_resolver,
|
| + &socket_factory, NULL);
|
| + // Now if I check out 1 socket from 3 different groups, the next request
|
| + // will leave us stalled.
|
| +
|
| + TestCompletionCallback callback1;
|
| + HostPortPair host_port1("1.com", 80);
|
| + scoped_refptr<TransportSocketParams> params1(
|
| + new TransportSocketParams(host_port1, MEDIUM, false, false));
|
| + scoped_ptr<ClientSocketHandle> connection1(new ClientSocketHandle);
|
| + EXPECT_EQ(ERR_IO_PENDING,
|
| + connection1->Init(host_port1.ToString(), params1, MEDIUM,
|
| + callback1.callback(), &pool, log.bound()));
|
| + EXPECT_EQ(OK, callback1.WaitForResult());
|
| + EXPECT_FALSE(pool.IsStalled());
|
| + EXPECT_TRUE(connection1->is_initialized());
|
| + EXPECT_TRUE(connection1->socket());
|
| +
|
| + TestCompletionCallback callback2;
|
| + HostPortPair host_port2("2.com", 80);
|
| + scoped_refptr<TransportSocketParams> params2(
|
| + new TransportSocketParams(host_port2, MEDIUM, false, false));
|
| + scoped_ptr<ClientSocketHandle> connection2(new ClientSocketHandle);
|
| + EXPECT_EQ(ERR_IO_PENDING,
|
| + connection2->Init(host_port2.ToString(), params2, MEDIUM,
|
| + callback2.callback(), &pool, log.bound()));
|
| + EXPECT_EQ(OK, callback2.WaitForResult());
|
| + EXPECT_FALSE(pool.IsStalled());
|
| +
|
| + TestCompletionCallback callback3;
|
| + HostPortPair host_port3("3.com", 80);
|
| + scoped_refptr<TransportSocketParams> params3(
|
| + new TransportSocketParams(host_port3, MEDIUM, false, false));
|
| + scoped_ptr<ClientSocketHandle> connection3(new ClientSocketHandle);
|
| + EXPECT_EQ(ERR_IO_PENDING,
|
| + connection3->Init(host_port3.ToString(), params3, MEDIUM,
|
| + callback3.callback(), &pool, log.bound()));
|
| + EXPECT_EQ(OK, callback3.WaitForResult());
|
| + EXPECT_FALSE(pool.IsStalled());
|
| +
|
| + TestCompletionCallback callback4;
|
| + HostPortPair host_port4("4.com", 80);
|
| + scoped_refptr<TransportSocketParams> params4(
|
| + new TransportSocketParams(host_port4, MEDIUM, false, false));
|
| + scoped_ptr<ClientSocketHandle> connection4(new ClientSocketHandle);
|
| + EXPECT_EQ(ERR_IO_PENDING,
|
| + connection4->Init(host_port4.ToString(), params4, MEDIUM,
|
| + callback4.callback(), &pool, log.bound()));
|
| + EXPECT_TRUE(pool.IsStalled());
|
| +
|
| + // Return 1 socket to the pool so that we are no longer stalled
|
| + connection3->socket()->Disconnect();
|
| + connection3->Reset();
|
| + EXPECT_EQ(OK, callback4.WaitForResult());
|
| + EXPECT_FALSE(pool.IsStalled());
|
| +
|
| + // Now, wrap one of the sockets in a SpdySession
|
| + HttpServerPropertiesImpl props;
|
| + SpdySessionPool spdy_session_pool(&host_resolver, NULL, &props);
|
| + HostPortProxyPair pair1(host_port1, ProxyServer::Direct());
|
| + EXPECT_FALSE(spdy_session_pool.HasSession(pair1));
|
| + scoped_refptr<SpdySession> session1 =
|
| + spdy_session_pool.Get(pair1, log.bound());
|
| + EXPECT_TRUE(spdy_session_pool.HasSession(pair1));
|
| + EXPECT_EQ(OK,
|
| + session1->InitializeWithSocket(connection1.release(), false, OK));
|
| + session1 = NULL;
|
| + EXPECT_TRUE(spdy_session_pool.HasSession(pair1));
|
| +
|
| + // The SpdySession is now idle. When we request the next socket from the
|
| + // transport pool, the session will be closed via CloseOneIdleConnection().
|
| + TestCompletionCallback callback5;
|
| + HostPortPair host_port5("5.com", 80);
|
| + scoped_refptr<TransportSocketParams> params5(
|
| + new TransportSocketParams(host_port5, MEDIUM, false, false));
|
| + scoped_ptr<ClientSocketHandle> connection5(new ClientSocketHandle);
|
| + EXPECT_EQ(ERR_IO_PENDING,
|
| + connection5->Init(host_port5.ToString(), params5, MEDIUM,
|
| + callback5.callback(), &pool, log.bound()));
|
| + EXPECT_FALSE(pool.IsStalled());
|
| + EXPECT_EQ(OK, callback5.WaitForResult());
|
| + EXPECT_FALSE(spdy_session_pool.HasSession(pair1));
|
| + EXPECT_FALSE(pool.IsStalled());
|
| +
|
| + // Now, wrap one of the sockets in a SpdySession
|
| + HostPortProxyPair pair2(host_port2, ProxyServer::Direct());
|
| + EXPECT_FALSE(spdy_session_pool.HasSession(pair2));
|
| + scoped_refptr<SpdySession> session2 =
|
| + spdy_session_pool.Get(pair2, log.bound());
|
| + EXPECT_TRUE(spdy_session_pool.HasSession(pair2));
|
| + EXPECT_EQ(OK,
|
| + session2->InitializeWithSocket(connection2.release(), false, OK));
|
| +
|
| + // Manually remove the socket from the pool. This does *not* return the
|
| + // transport socket. It will be returned only when the SpdySession is
|
| + // destructed.
|
| + session2->RemoveFromPool();
|
| + EXPECT_FALSE(spdy_session_pool.HasSession(pair2));
|
| +
|
| + // Although there are no active streams on the session, the pool does not
|
| + // hold a reference. This means that CloseOneIdleConnection should not
|
| + // return true, and this request should stall.
|
| + TestCompletionCallback callback6;
|
| + HostPortPair host_port6("6.com", 80);
|
| + scoped_refptr<TransportSocketParams> params6(
|
| + new TransportSocketParams(host_port5, MEDIUM, false, false));
|
| + scoped_ptr<ClientSocketHandle> connection6(new ClientSocketHandle);
|
| + EXPECT_EQ(ERR_IO_PENDING,
|
| + connection6->Init(host_port6.ToString(), params6, MEDIUM,
|
| + callback6.callback(), &pool, log.bound()));
|
| + EXPECT_TRUE(pool.IsStalled());
|
| +
|
| + // But now if we drop our reference to the session, it will be destructed
|
| + // and the transport socket will return to the pool, unblocking this
|
| + // request.
|
| + session2 = NULL;
|
| + EXPECT_EQ(OK, callback6.WaitForResult());
|
| + EXPECT_FALSE(pool.IsStalled());
|
| +}
|
| +
|
| } // namespace net
|
|
|