Chromium Code Reviews| Index: net/quic/quic_chromium_client_session_test.cc |
| diff --git a/net/quic/quic_chromium_client_session_test.cc b/net/quic/quic_chromium_client_session_test.cc |
| index 113e99812d490062e0398d3b54538bc5d8273fd7..7536b00b2bc517e79304ba713f02cfd4d7fb28aa 100644 |
| --- a/net/quic/quic_chromium_client_session_test.cc |
| +++ b/net/quic/quic_chromium_client_session_test.cc |
| @@ -22,12 +22,18 @@ |
| #include "net/quic/crypto/quic_decrypter.h" |
| #include "net/quic/crypto/quic_encrypter.h" |
| #include "net/quic/crypto/quic_server_info.h" |
| +#include "net/quic/quic_connection_helper.h" |
| +#include "net/quic/quic_default_packet_writer.h" |
| #include "net/quic/quic_flags.h" |
| +#include "net/quic/quic_http_utils.h" |
| #include "net/quic/quic_packet_reader.h" |
| +#include "net/quic/quic_packet_writer.h" |
| #include "net/quic/quic_protocol.h" |
| #include "net/quic/test_tools/crypto_test_utils.h" |
| +#include "net/quic/test_tools/mock_crypto_client_stream_factory.h" |
| #include "net/quic/test_tools/quic_chromium_client_session_peer.h" |
| #include "net/quic/test_tools/quic_spdy_session_peer.h" |
| +#include "net/quic/test_tools/quic_test_packet_maker.h" |
| #include "net/quic/test_tools/quic_test_utils.h" |
| #include "net/quic/test_tools/simple_quic_framer.h" |
| #include "net/socket/socket_test_util.h" |
| @@ -41,22 +47,49 @@ namespace net { |
| namespace test { |
| namespace { |
| +const IPEndPoint kIpEndPoint(IPAddressNumber(kIPv4AddressSize, 0), 0); |
| const char kServerHostname[] = "test.example.com"; |
| const uint16_t kServerPort = 443; |
| +const size_t kMaxReadersPerQuicSession = 5; |
| + |
| +class DefaultPacketWriterFactory : public QuicConnection::PacketWriterFactory { |
| + public: |
| + explicit DefaultPacketWriterFactory(DatagramClientSocket* socket) |
| + : socket_(socket) {} |
| + ~DefaultPacketWriterFactory() override {} |
| + |
| + QuicPacketWriter* Create(QuicConnection* connection) const override { |
| + scoped_ptr<net::QuicDefaultPacketWriter> writer( |
| + new net::QuicDefaultPacketWriter(socket_)); |
| + writer->SetConnection(connection); |
| + return writer.release(); |
| + } |
| + |
| + private: |
| + DatagramClientSocket* socket_; |
| +}; |
| class QuicChromiumClientSessionTest |
| : public ::testing::TestWithParam<QuicVersion> { |
| protected: |
| QuicChromiumClientSessionTest() |
| : crypto_config_(CryptoTestUtils::ProofVerifierForTesting()), |
| - connection_(new PacketSavingConnection(&helper_, |
| - Perspective::IS_CLIENT, |
| - SupportedVersions(GetParam()))), |
| + socket_(GetSocket()), |
| + random_(0), |
| + helper_(base::ThreadTaskRunnerHandle::Get().get(), &clock_, &random_), |
| + writer_factory_(socket_.get()), |
| + connection_(new QuicConnection(0, |
| + kIpEndPoint, |
| + &helper_, |
| + writer_factory_, |
| + true, |
| + Perspective::IS_CLIENT, |
| + SupportedVersions(GetParam()))), |
| session_( |
| connection_, |
| - GetSocket().Pass(), |
| + std::move(socket_), |
|
Ryan Hamilton
2016/01/08 05:01:06
I'm a bit confused by this. If you move socket_ in
Jana
2016/01/09 02:06:53
Not really -- it's initialized above and used here
|
| /*stream_factory=*/nullptr, |
| - /*crypto_client_stream_factory=*/nullptr, |
| + &crypto_client_stream_factory_, |
| &clock_, |
| &transport_security_state_, |
| make_scoped_ptr((QuicServerInfo*)nullptr), |
| @@ -71,10 +104,17 @@ class QuicChromiumClientSessionTest |
| base::TimeTicks::Now(), |
| base::ThreadTaskRunnerHandle::Get().get(), |
| /*socket_performance_watcher=*/nullptr, |
| - &net_log_) { |
| - session_.Initialize(); |
| + &net_log_), |
| + maker_(GetParam(), 0, &clock_, kServerHostname) { |
| + scoped_refptr<X509Certificate> cert( |
| + ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem")); |
| + verify_details_.cert_verify_result.verified_cert = cert; |
| + verify_details_.cert_verify_result.is_issued_by_known_root = true; |
| + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details_); |
| // Advance the time, because timers do not like uninitialized times. |
| - connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1)); |
| + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); |
| + session_.Initialize(); |
| + session_.StartReading(); |
| } |
| void TearDown() override { |
| @@ -82,33 +122,72 @@ class QuicChromiumClientSessionTest |
| } |
| scoped_ptr<DatagramClientSocket> GetSocket() { |
| - socket_factory_.AddSocketDataProvider(&socket_data_); |
| - return socket_factory_.CreateDatagramClientSocket( |
| - DatagramSocket::DEFAULT_BIND, base::Bind(&base::RandInt), &net_log_, |
| - NetLog::Source()); |
| + reads_[0] = MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0); |
| + socket_data_.reset( |
| + new StaticSocketDataProvider(reads_, arraysize(reads_), nullptr, 0)); |
| + socket_factory_.AddSocketDataProvider(socket_data_.get()); |
| + scoped_ptr<DatagramClientSocket> socket = |
| + socket_factory_.CreateDatagramClientSocket(DatagramSocket::DEFAULT_BIND, |
| + base::Bind(&base::RandInt), |
| + &net_log_, NetLog::Source()); |
| + socket->Connect(kIpEndPoint); |
| + return socket; |
| } |
| void CompleteCryptoHandshake() { |
| - ASSERT_EQ(ERR_IO_PENDING, |
| - session_.CryptoConnect(false, callback_.callback())); |
| - CryptoTestUtils::FakeServerOptions server_options; |
| - CryptoTestUtils::HandshakeWithFakeServer( |
| - &helper_, connection_, session_.GetCryptoStream(), server_options); |
| - ASSERT_EQ(OK, callback_.WaitForResult()); |
| + ASSERT_EQ(OK, session_.CryptoConnect(false, callback_.callback())); |
| + } |
| + |
| + QuicPacketWriter* CreateQuicPacketWriter(DatagramClientSocket* socket, |
| + QuicConnection* connection) const { |
| + scoped_ptr<QuicDefaultPacketWriter> writer( |
| + new QuicDefaultPacketWriter(socket)); |
| + writer->SetConnection(connection); |
| + return writer.release(); |
| + } |
| + |
| + scoped_ptr<QuicEncryptedPacket> ConstructGetRequestPacket( |
| + QuicPacketNumber packet_number, |
| + QuicStreamId stream_id, |
| + bool should_include_version, |
| + bool fin) { |
| + SpdyHeaderBlock headers = maker_.GetRequestHeaders("GET", "https", "/"); |
| + SpdyPriority priority = |
| + ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY); |
| + return maker_.MakeRequestHeadersPacket(packet_number, stream_id, |
| + should_include_version, fin, |
| + priority, headers); |
| + } |
| + |
| + scoped_ptr<QuicEncryptedPacket> ConstructOkResponsePacket( |
| + QuicPacketNumber packet_number, |
| + QuicStreamId stream_id, |
| + bool should_include_version, |
| + bool fin) { |
| + SpdyHeaderBlock headers = maker_.GetResponseHeaders("200 OK"); |
| + return maker_.MakeResponseHeadersPacket( |
| + packet_number, stream_id, should_include_version, fin, headers); |
| } |
| - MockConnectionHelper helper_; |
| QuicCryptoClientConfig crypto_config_; |
| - PacketSavingConnection* connection_; |
| TestNetLog net_log_; |
| + BoundTestNetLog bound_net_log_; |
| MockClientSocketFactory socket_factory_; |
| - StaticSocketDataProvider socket_data_; |
| - TransportSecurityState transport_security_state_; |
| - QuicChromiumClientSession session_; |
| + MockRead reads_[1]; |
|
Ryan Hamilton
2016/01/08 05:01:06
Does this need to be an array?
Jana
2016/01/09 02:06:53
Good point -- changed to scoped_ptr
|
| + scoped_ptr<StaticSocketDataProvider> socket_data_; |
| + scoped_ptr<DatagramClientSocket> socket_; |
| MockClock clock_; |
| MockRandom random_; |
| + QuicConnectionHelper helper_; |
| + DefaultPacketWriterFactory writer_factory_; |
| + QuicConnection* connection_; |
| + TransportSecurityState transport_security_state_; |
| + MockCryptoClientStreamFactory crypto_client_stream_factory_; |
| + QuicChromiumClientSession session_; |
| QuicConnectionVisitorInterface* visitor_; |
| TestCompletionCallback callback_; |
| + QuicTestPacketMaker maker_; |
| + ProofVerifyDetailsChromium verify_details_; |
| }; |
| INSTANTIATE_TEST_CASE_P(Tests, |
| @@ -121,9 +200,10 @@ TEST_P(QuicChromiumClientSessionTest, CryptoConnect) { |
| TEST_P(QuicChromiumClientSessionTest, MaxNumStreams) { |
| CompleteCryptoHandshake(); |
| + const size_t kMaxOpenStreams = session_.get_max_open_streams(); |
| std::vector<QuicReliableClientStream*> streams; |
| - for (size_t i = 0; i < kDefaultMaxStreamsPerConnection; i++) { |
| + for (size_t i = 0; i < kMaxOpenStreams; i++) { |
| QuicReliableClientStream* stream = |
| session_.CreateOutgoingDynamicStream(kDefaultPriority); |
| EXPECT_TRUE(stream); |
| @@ -131,8 +211,7 @@ TEST_P(QuicChromiumClientSessionTest, MaxNumStreams) { |
| } |
| EXPECT_FALSE(session_.CreateOutgoingDynamicStream(kDefaultPriority)); |
| - EXPECT_EQ(kDefaultMaxStreamsPerConnection, |
| - session_.GetNumOpenOutgoingStreams()); |
| + EXPECT_EQ(kMaxOpenStreams, session_.GetNumOpenOutgoingStreams()); |
| // Close a stream and ensure I can now open a new one. |
| QuicStreamId stream_id = streams[0]->id(); |
| @@ -141,16 +220,16 @@ TEST_P(QuicChromiumClientSessionTest, MaxNumStreams) { |
| EXPECT_FALSE(session_.CreateOutgoingDynamicStream(kDefaultPriority)); |
| QuicRstStreamFrame rst1(stream_id, QUIC_STREAM_NO_ERROR, 0); |
| session_.OnRstStream(rst1); |
| - EXPECT_EQ(kDefaultMaxStreamsPerConnection - 1, |
| - session_.GetNumOpenOutgoingStreams()); |
| + EXPECT_EQ(kMaxOpenStreams - 1, session_.GetNumOpenOutgoingStreams()); |
| EXPECT_TRUE(session_.CreateOutgoingDynamicStream(kDefaultPriority)); |
| } |
| TEST_P(QuicChromiumClientSessionTest, MaxNumStreamsViaRequest) { |
| CompleteCryptoHandshake(); |
| + const size_t kMaxOpenStreams = session_.get_max_open_streams(); |
| std::vector<QuicReliableClientStream*> streams; |
| - for (size_t i = 0; i < kDefaultMaxStreamsPerConnection; i++) { |
| + for (size_t i = 0; i < kMaxOpenStreams; i++) { |
| QuicReliableClientStream* stream = |
| session_.CreateOutgoingDynamicStream(kDefaultPriority); |
| EXPECT_TRUE(stream); |
| @@ -274,6 +353,102 @@ TEST_P(QuicChromiumClientSessionTest, ConnectionPooledWithMatchingPin) { |
| EXPECT_TRUE(session_.CanPool("mail.example.org", PRIVACY_MODE_DISABLED)); |
| } |
| +TEST_P(QuicChromiumClientSessionTest, MigrateToSocket) { |
| + CompleteCryptoHandshake(); |
| + |
| + char data[] = "ABCD"; |
| + scoped_ptr<QuicEncryptedPacket> ping_in( |
| + maker_.MakePingPacket(1, /*include_version=*/false)); |
| + scoped_ptr<QuicEncryptedPacket> ping_out( |
| + maker_.MakePingPacket(1, /*include_version=*/false)); |
|
Ryan Hamilton
2016/01/08 05:01:06
Since this is the same packet as ping_in, you can
Jana
2016/01/09 02:06:53
Ah -- yes, of course. Left over from changing this
|
| + scoped_ptr<QuicEncryptedPacket> ack_and_data_out(maker_.MakeAckAndDataPacket( |
| + 2, false, 5, 1, 1, false, 0, StringPiece(data))); |
| + MockRead reads[] = { |
| + MockRead(SYNCHRONOUS, ping_in->data(), ping_in->length(), 0), |
| + MockRead(SYNCHRONOUS, ERR_IO_PENDING, 1)}; |
| + MockWrite writes[] = { |
| + MockWrite(SYNCHRONOUS, ping_out->data(), ping_out->length(), 2), |
| + MockWrite(SYNCHRONOUS, ack_and_data_out->data(), |
| + ack_and_data_out->length(), 3)}; |
| + StaticSocketDataProvider socket_data(reads, arraysize(reads), writes, |
| + arraysize(writes)); |
| + socket_factory_.AddSocketDataProvider(&socket_data); |
| + |
| + // Create connected socket. |
| + scoped_ptr<DatagramClientSocket> new_socket = |
| + socket_factory_.CreateDatagramClientSocket(DatagramSocket::DEFAULT_BIND, |
| + base::Bind(&base::RandInt), |
| + &net_log_, NetLog::Source()); |
| + EXPECT_EQ(OK, new_socket->Connect(kIpEndPoint)); |
| + |
| + // Create reader and writer. |
| + scoped_ptr<QuicPacketReader> new_reader(new QuicPacketReader( |
| + new_socket.get(), &clock_, &session_, kQuicYieldAfterPacketsRead, |
| + QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds), |
| + bound_net_log_.bound())); |
| + scoped_ptr<QuicPacketWriter> new_writer( |
| + CreateQuicPacketWriter(new_socket.get(), session_.connection())); |
| + |
| + // Migrate session. |
| + EXPECT_TRUE(session_.MigrateToSocket( |
| + std::move(new_socket), std::move(new_reader), std::move(new_writer))); |
| + |
| + // Write data to session. |
| + struct iovec iov[1]; |
| + iov[0].iov_base = data; |
| + iov[0].iov_len = 4; |
| + session_.WritevData(5, QuicIOVector(iov, arraysize(iov), 4), 0, false, |
| + MAY_FEC_PROTECT, nullptr); |
| + |
| + EXPECT_TRUE(socket_data.AllReadDataConsumed()); |
| + EXPECT_TRUE(socket_data.AllWriteDataConsumed()); |
| +} |
| + |
| +TEST_P(QuicChromiumClientSessionTest, MigrateToSocketMaxReaders) { |
| + CompleteCryptoHandshake(); |
| + |
| + for (size_t i = 0; i < kMaxReadersPerQuicSession; ++i) { |
| + MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 1)}; |
| + scoped_ptr<QuicEncryptedPacket> ping_out( |
| + maker_.MakePingPacket(i + 1, /*include_version=*/true)); |
| + MockWrite writes[] = { |
| + MockWrite(SYNCHRONOUS, ping_out->data(), ping_out->length(), i + 2)}; |
| + StaticSocketDataProvider socket_data(reads, arraysize(reads), writes, |
| + arraysize(writes)); |
| + socket_factory_.AddSocketDataProvider(&socket_data); |
| + |
| + // Create connected socket. |
| + scoped_ptr<DatagramClientSocket> new_socket = |
| + socket_factory_.CreateDatagramClientSocket(DatagramSocket::DEFAULT_BIND, |
| + base::Bind(&base::RandInt), |
| + &net_log_, NetLog::Source()); |
| + EXPECT_EQ(OK, new_socket->Connect(kIpEndPoint)); |
| + |
| + // Create reader and writer. |
| + scoped_ptr<QuicPacketReader> new_reader(new QuicPacketReader( |
| + new_socket.get(), &clock_, &session_, kQuicYieldAfterPacketsRead, |
| + QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds), |
| + bound_net_log_.bound())); |
| + scoped_ptr<QuicPacketWriter> new_writer( |
| + CreateQuicPacketWriter(new_socket.get(), session_.connection())); |
| + |
| + // Migrate session. |
| + if (i < kMaxReadersPerQuicSession - 1) { |
| + EXPECT_TRUE(session_.MigrateToSocket( |
| + std::move(new_socket), std::move(new_reader), std::move(new_writer))); |
| + EXPECT_TRUE(socket_data.AllReadDataConsumed()); |
| + EXPECT_TRUE(socket_data.AllWriteDataConsumed()); |
| + } else { |
| + // Max readers exceeded. |
| + EXPECT_FALSE(session_.MigrateToSocket( |
| + std::move(new_socket), std::move(new_reader), std::move(new_writer))); |
| + |
| + EXPECT_FALSE(socket_data.AllReadDataConsumed()); |
| + EXPECT_FALSE(socket_data.AllWriteDataConsumed()); |
| + } |
| + } |
| +} |
| + |
| } // namespace |
| } // namespace test |
| } // namespace net |