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 ba831efa0c48428763395b3634873c1f1364bef6..356b69a69efc6b7ceb852635147bc52e0ae772f1 100644 |
--- a/net/quic/quic_chromium_client_session_test.cc |
+++ b/net/quic/quic_chromium_client_session_test.cc |
@@ -22,13 +22,19 @@ |
#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_crypto_client_stream_factory.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" |
@@ -42,74 +48,106 @@ 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()))), |
- session_( |
- connection_, |
- GetSocket(), |
- /*stream_factory=*/nullptr, |
- QuicCryptoClientStreamFactory::GetDefaultFactory(), |
- &clock_, |
- &transport_security_state_, |
- make_scoped_ptr((QuicServerInfo*)nullptr), |
- QuicServerId(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED), |
- kQuicYieldAfterPacketsRead, |
- QuicTime::Delta::FromMilliseconds( |
- kQuicYieldAfterDurationMilliseconds), |
- /*cert_verify_flags=*/0, |
- DefaultQuicConfig(), |
- &crypto_config_, |
- "CONNECTION_UNKNOWN", |
- base::TimeTicks::Now(), |
- base::ThreadTaskRunnerHandle::Get().get(), |
- /*socket_performance_watcher=*/nullptr, |
- &net_log_) { |
- session_.Initialize(); |
+ default_read_(new MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)), |
+ socket_data_( |
+ new SequencedSocketData(default_read_.get(), 1, nullptr, 0)), |
+ random_(0), |
+ helper_(base::ThreadTaskRunnerHandle::Get().get(), &clock_, &random_), |
+ maker_(GetParam(), 0, &clock_, kServerHostname) {} |
+ |
+ void Initialize() { |
+ 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); |
+ DefaultPacketWriterFactory writer_factory(socket.get()); |
+ QuicConnection* connection = new QuicConnection( |
+ 0, kIpEndPoint, &helper_, writer_factory, true, Perspective::IS_CLIENT, |
+ SupportedVersions(GetParam())); |
+ session_.reset(new QuicChromiumClientSession( |
+ connection, std::move(socket), |
+ /*stream_factory=*/nullptr, &crypto_client_stream_factory_, &clock_, |
+ &transport_security_state_, make_scoped_ptr((QuicServerInfo*)nullptr), |
+ QuicServerId(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED), |
+ kQuicYieldAfterPacketsRead, |
+ QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds), |
+ /*cert_verify_flags=*/0, DefaultQuicConfig(), &crypto_config_, |
+ "CONNECTION_UNKNOWN", base::TimeTicks::Now(), |
+ base::ThreadTaskRunnerHandle::Get().get(), |
+ /*socket_performance_watcher=*/nullptr, &net_log_)); |
+ |
+ 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; |
// 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 { |
- session_.CloseSessionOnError(ERR_ABORTED, QUIC_INTERNAL_ERROR); |
+ session_->CloseSessionOnError(ERR_ABORTED, QUIC_INTERNAL_ERROR); |
} |
- scoped_ptr<DatagramClientSocket> GetSocket() { |
- socket_factory_.AddSocketDataProvider(&socket_data_); |
- return socket_factory_.CreateDatagramClientSocket( |
- DatagramSocket::DEFAULT_BIND, base::Bind(&base::RandInt), &net_log_, |
- NetLog::Source()); |
+ void CompleteCryptoHandshake() { |
+ ASSERT_EQ(OK, session_->CryptoConnect(false, callback_.callback())); |
} |
- 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()); |
+ QuicPacketWriter* CreateQuicPacketWriter(DatagramClientSocket* socket, |
+ QuicConnection* connection) const { |
+ scoped_ptr<QuicDefaultPacketWriter> writer( |
+ new QuicDefaultPacketWriter(socket)); |
+ writer->SetConnection(connection); |
+ return writer.release(); |
} |
- 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_; |
+ scoped_ptr<MockRead> default_read_; |
+ scoped_ptr<SequencedSocketData> socket_data_; |
MockClock clock_; |
MockRandom random_; |
+ QuicConnectionHelper helper_; |
+ scoped_ptr<DefaultPacketWriterFactory> writer_factory_; |
+ TransportSecurityState transport_security_state_; |
+ MockCryptoClientStreamFactory crypto_client_stream_factory_; |
+ scoped_ptr<QuicChromiumClientSession> session_; |
QuicConnectionVisitorInterface* visitor_; |
TestCompletionCallback callback_; |
+ QuicTestPacketMaker maker_; |
+ ProofVerifyDetailsChromium verify_details_; |
}; |
INSTANTIATE_TEST_CASE_P(Tests, |
@@ -117,43 +155,62 @@ INSTANTIATE_TEST_CASE_P(Tests, |
::testing::ValuesIn(QuicSupportedVersions())); |
TEST_P(QuicChromiumClientSessionTest, CryptoConnect) { |
+ Initialize(); |
CompleteCryptoHandshake(); |
} |
TEST_P(QuicChromiumClientSessionTest, MaxNumStreams) { |
+ MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; |
+ scoped_ptr<QuicEncryptedPacket> client_rst(maker_.MakeRstPacket( |
+ 1, true, kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT)); |
+ MockWrite writes[] = { |
+ MockWrite(ASYNC, client_rst->data(), client_rst->length(), 1)}; |
+ socket_data_.reset(new SequencedSocketData(reads, arraysize(reads), writes, |
+ arraysize(writes))); |
+ |
+ Initialize(); |
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); |
+ session_->CreateOutgoingDynamicStream(kDefaultPriority); |
EXPECT_TRUE(stream); |
streams.push_back(stream); |
} |
- EXPECT_FALSE(session_.CreateOutgoingDynamicStream(kDefaultPriority)); |
+ 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(); |
- session_.CloseStream(stream_id); |
+ session_->CloseStream(stream_id); |
- EXPECT_FALSE(session_.CreateOutgoingDynamicStream(kDefaultPriority)); |
+ EXPECT_FALSE(session_->CreateOutgoingDynamicStream(kDefaultPriority)); |
QuicRstStreamFrame rst1(stream_id, QUIC_STREAM_NO_ERROR, 0); |
- session_.OnRstStream(rst1); |
- EXPECT_EQ(kDefaultMaxStreamsPerConnection - 1, |
- session_.GetNumOpenOutgoingStreams()); |
- EXPECT_TRUE(session_.CreateOutgoingDynamicStream(kDefaultPriority)); |
+ session_->OnRstStream(rst1); |
+ EXPECT_EQ(kMaxOpenStreams - 1, session_->GetNumOpenOutgoingStreams()); |
+ EXPECT_TRUE(session_->CreateOutgoingDynamicStream(kDefaultPriority)); |
} |
TEST_P(QuicChromiumClientSessionTest, MaxNumStreamsViaRequest) { |
+ MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; |
+ scoped_ptr<QuicEncryptedPacket> client_rst(maker_.MakeRstPacket( |
+ 1, true, kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT)); |
+ MockWrite writes[] = { |
+ MockWrite(ASYNC, client_rst->data(), client_rst->length(), 1)}; |
+ socket_data_.reset(new SequencedSocketData(reads, arraysize(reads), writes, |
+ arraysize(writes))); |
+ |
+ Initialize(); |
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); |
+ session_->CreateOutgoingDynamicStream(kDefaultPriority); |
EXPECT_TRUE(stream); |
streams.push_back(stream); |
} |
@@ -162,30 +219,32 @@ TEST_P(QuicChromiumClientSessionTest, MaxNumStreamsViaRequest) { |
QuicChromiumClientSession::StreamRequest stream_request; |
TestCompletionCallback callback; |
ASSERT_EQ(ERR_IO_PENDING, |
- stream_request.StartRequest(session_.GetWeakPtr(), &stream, |
+ stream_request.StartRequest(session_->GetWeakPtr(), &stream, |
callback.callback())); |
// Close a stream and ensure I can now open a new one. |
QuicStreamId stream_id = streams[0]->id(); |
- session_.CloseStream(stream_id); |
+ session_->CloseStream(stream_id); |
QuicRstStreamFrame rst1(stream_id, QUIC_STREAM_NO_ERROR, 0); |
- session_.OnRstStream(rst1); |
+ session_->OnRstStream(rst1); |
ASSERT_TRUE(callback.have_result()); |
EXPECT_EQ(OK, callback.WaitForResult()); |
EXPECT_TRUE(stream != nullptr); |
} |
TEST_P(QuicChromiumClientSessionTest, GoAwayReceived) { |
+ Initialize(); |
CompleteCryptoHandshake(); |
// After receiving a GoAway, I should no longer be able to create outgoing |
// streams. |
- session_.connection()->OnGoAwayFrame( |
+ session_->connection()->OnGoAwayFrame( |
QuicGoAwayFrame(QUIC_PEER_GOING_AWAY, 1u, "Going away.")); |
- EXPECT_EQ(nullptr, session_.CreateOutgoingDynamicStream(kDefaultPriority)); |
+ EXPECT_EQ(nullptr, session_->CreateOutgoingDynamicStream(kDefaultPriority)); |
} |
TEST_P(QuicChromiumClientSessionTest, CanPool) { |
+ Initialize(); |
// Load a cert that is valid for: |
// www.example.org |
// mail.example.org |
@@ -197,16 +256,17 @@ TEST_P(QuicChromiumClientSessionTest, CanPool) { |
ASSERT_TRUE(details.cert_verify_result.verified_cert.get()); |
CompleteCryptoHandshake(); |
- session_.OnProofVerifyDetailsAvailable(details); |
+ session_->OnProofVerifyDetailsAvailable(details); |
- EXPECT_TRUE(session_.CanPool("www.example.org", PRIVACY_MODE_DISABLED)); |
- EXPECT_FALSE(session_.CanPool("www.example.org", PRIVACY_MODE_ENABLED)); |
- EXPECT_TRUE(session_.CanPool("mail.example.org", PRIVACY_MODE_DISABLED)); |
- EXPECT_TRUE(session_.CanPool("mail.example.com", PRIVACY_MODE_DISABLED)); |
- EXPECT_FALSE(session_.CanPool("mail.google.com", PRIVACY_MODE_DISABLED)); |
+ EXPECT_TRUE(session_->CanPool("www.example.org", PRIVACY_MODE_DISABLED)); |
+ EXPECT_FALSE(session_->CanPool("www.example.org", PRIVACY_MODE_ENABLED)); |
+ EXPECT_TRUE(session_->CanPool("mail.example.org", PRIVACY_MODE_DISABLED)); |
+ EXPECT_TRUE(session_->CanPool("mail.example.com", PRIVACY_MODE_DISABLED)); |
+ EXPECT_FALSE(session_->CanPool("mail.google.com", PRIVACY_MODE_DISABLED)); |
} |
TEST_P(QuicChromiumClientSessionTest, ConnectionPooledWithTlsChannelId) { |
+ Initialize(); |
// Load a cert that is valid for: |
// www.example.org |
// mail.example.org |
@@ -218,17 +278,19 @@ TEST_P(QuicChromiumClientSessionTest, ConnectionPooledWithTlsChannelId) { |
ASSERT_TRUE(details.cert_verify_result.verified_cert.get()); |
CompleteCryptoHandshake(); |
- session_.OnProofVerifyDetailsAvailable(details); |
- QuicChromiumClientSessionPeer::SetHostname(&session_, "www.example.org"); |
- QuicChromiumClientSessionPeer::SetChannelIDSent(&session_, true); |
- |
- EXPECT_TRUE(session_.CanPool("www.example.org", PRIVACY_MODE_DISABLED)); |
- EXPECT_TRUE(session_.CanPool("mail.example.org", PRIVACY_MODE_DISABLED)); |
- EXPECT_FALSE(session_.CanPool("mail.example.com", PRIVACY_MODE_DISABLED)); |
- EXPECT_FALSE(session_.CanPool("mail.google.com", PRIVACY_MODE_DISABLED)); |
+ session_->OnProofVerifyDetailsAvailable(details); |
+ QuicChromiumClientSessionPeer::SetHostname(session_.get(), "www.example.org"); |
+ QuicChromiumClientSessionPeer::SetChannelIDSent(session_.get(), true); |
+ |
+ EXPECT_TRUE(session_->CanPool("www.example.org", PRIVACY_MODE_DISABLED)); |
+ EXPECT_TRUE(session_->CanPool("mail.example.org", PRIVACY_MODE_DISABLED)); |
+ EXPECT_FALSE(session_->CanPool("mail.example.com", PRIVACY_MODE_DISABLED)); |
+ EXPECT_FALSE(session_->CanPool("mail.google.com", PRIVACY_MODE_DISABLED)); |
} |
TEST_P(QuicChromiumClientSessionTest, ConnectionNotPooledWithDifferentPin) { |
+ Initialize(); |
+ |
uint8_t primary_pin = 1; |
uint8_t backup_pin = 2; |
uint8_t bad_pin = 3; |
@@ -245,14 +307,16 @@ TEST_P(QuicChromiumClientSessionTest, ConnectionNotPooledWithDifferentPin) { |
ASSERT_TRUE(details.cert_verify_result.verified_cert.get()); |
CompleteCryptoHandshake(); |
- session_.OnProofVerifyDetailsAvailable(details); |
- QuicChromiumClientSessionPeer::SetHostname(&session_, "www.example.org"); |
- QuicChromiumClientSessionPeer::SetChannelIDSent(&session_, true); |
+ session_->OnProofVerifyDetailsAvailable(details); |
+ QuicChromiumClientSessionPeer::SetHostname(session_.get(), "www.example.org"); |
+ QuicChromiumClientSessionPeer::SetChannelIDSent(session_.get(), true); |
- EXPECT_FALSE(session_.CanPool("mail.example.org", PRIVACY_MODE_DISABLED)); |
+ EXPECT_FALSE(session_->CanPool("mail.example.org", PRIVACY_MODE_DISABLED)); |
} |
TEST_P(QuicChromiumClientSessionTest, ConnectionPooledWithMatchingPin) { |
+ Initialize(); |
+ |
uint8_t primary_pin = 1; |
uint8_t backup_pin = 2; |
AddPin(&transport_security_state_, "mail.example.org", primary_pin, |
@@ -268,11 +332,208 @@ TEST_P(QuicChromiumClientSessionTest, ConnectionPooledWithMatchingPin) { |
ASSERT_TRUE(details.cert_verify_result.verified_cert.get()); |
CompleteCryptoHandshake(); |
- session_.OnProofVerifyDetailsAvailable(details); |
- QuicChromiumClientSessionPeer::SetHostname(&session_, "www.example.org"); |
- QuicChromiumClientSessionPeer::SetChannelIDSent(&session_, true); |
+ session_->OnProofVerifyDetailsAvailable(details); |
+ QuicChromiumClientSessionPeer::SetHostname(session_.get(), "www.example.org"); |
+ QuicChromiumClientSessionPeer::SetChannelIDSent(session_.get(), true); |
+ |
+ EXPECT_TRUE(session_->CanPool("mail.example.org", PRIVACY_MODE_DISABLED)); |
+} |
+ |
+TEST_P(QuicChromiumClientSessionTest, MigrateToSocket) { |
+ Initialize(); |
+ CompleteCryptoHandshake(); |
+ |
+ char data[] = "ABCD"; |
+ scoped_ptr<QuicEncryptedPacket> ping( |
+ maker_.MakePingPacket(1, /*include_version=*/false)); |
+ scoped_ptr<QuicEncryptedPacket> ack_and_data_out(maker_.MakeAckAndDataPacket( |
+ 2, false, 5, 1, 1, false, 0, StringPiece(data))); |
+ MockRead reads[] = {MockRead(SYNCHRONOUS, ping->data(), ping->length(), 0), |
+ MockRead(SYNCHRONOUS, ERR_IO_PENDING, 1)}; |
+ MockWrite writes[] = {MockWrite(SYNCHRONOUS, ping->data(), ping->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_.get(), 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) { |
+ Initialize(); |
+ 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_.get(), 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()); |
+ } |
+ } |
+} |
+ |
+TEST_P(QuicChromiumClientSessionTest, MigrateToSocketReadError) { |
+ scoped_ptr<QuicEncryptedPacket> ping( |
+ maker_.MakePingPacket(1, /*include_version=*/true)); |
+ MockRead old_reads[] = { |
+ MockRead(SYNCHRONOUS, ping->data(), ping->length(), 0), |
+ MockRead(ASYNC, ERR_IO_PENDING, 1), // causes reading to pause. |
+ MockRead(ASYNC, ERR_NETWORK_CHANGED, 2)}; |
+ socket_data_.reset( |
+ new SequencedSocketData(old_reads, arraysize(old_reads), nullptr, 0)); |
+ Initialize(); |
+ CompleteCryptoHandshake(); |
+ |
+ MockWrite writes[] = { |
+ MockWrite(SYNCHRONOUS, ping->data(), ping->length(), 1)}; |
+ MockRead new_reads[] = { |
+ MockRead(SYNCHRONOUS, ping->data(), ping->length(), 0), |
+ MockRead(ASYNC, ERR_IO_PENDING, 2), // pause reading. |
+ MockRead(ASYNC, ping->data(), ping->length(), 3), |
+ MockRead(ASYNC, ERR_IO_PENDING, 4), // pause reading |
+ MockRead(ASYNC, ERR_NETWORK_CHANGED, 5)}; |
+ SequencedSocketData new_socket_data(new_reads, arraysize(new_reads), writes, |
+ arraysize(writes)); |
+ socket_factory_.AddSocketDataProvider(&new_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_.get(), kQuicYieldAfterPacketsRead, |
+ QuicTime::Delta::FromMilliseconds(kQuicYieldAfterDurationMilliseconds), |
+ bound_net_log_.bound())); |
+ scoped_ptr<QuicPacketWriter> new_writer( |
+ CreateQuicPacketWriter(new_socket.get(), session_->connection())); |
+ |
+ // Store old socket and migrate session. |
+ EXPECT_TRUE(session_->MigrateToSocket( |
+ std::move(new_socket), std::move(new_reader), std::move(new_writer))); |
+ |
+ // Read error on old socket does not impact session. |
+ EXPECT_TRUE(socket_data_->IsPaused()); |
+ socket_data_->Resume(); |
+ EXPECT_TRUE(session_->connection()->connected()); |
+ EXPECT_TRUE(new_socket_data.IsPaused()); |
+ new_socket_data.Resume(); |
+ |
+ // Read error on new socket causes session close. |
+ EXPECT_TRUE(new_socket_data.IsPaused()); |
+ EXPECT_TRUE(session_->connection()->connected()); |
+ new_socket_data.Resume(); |
+ EXPECT_FALSE(session_->connection()->connected()); |
+ |
+ EXPECT_TRUE(socket_data_->AllReadDataConsumed()); |
+ EXPECT_TRUE(socket_data_->AllWriteDataConsumed()); |
+ EXPECT_TRUE(new_socket_data.AllReadDataConsumed()); |
+ EXPECT_TRUE(new_socket_data.AllWriteDataConsumed()); |
+} |
+ |
+TEST_P(QuicChromiumClientSessionTest, MigrateToSocketWriteError) { |
+ Initialize(); |
+ CompleteCryptoHandshake(); |
- EXPECT_TRUE(session_.CanPool("mail.example.org", PRIVACY_MODE_DISABLED)); |
+ scoped_ptr<QuicEncryptedPacket> ping( |
+ maker_.MakePingPacket(1, /*include_version=*/true)); |
+ MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; |
+ MockWrite writes[] = {MockWrite(SYNCHRONOUS, ping->data(), ping->length(), 1), |
+ MockWrite(SYNCHRONOUS, ERR_FAILED, 2)}; |
+ SequencedSocketData 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_.get(), 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 error on new socket causes session close. |
+ EXPECT_TRUE(session_->connection()->connected()); |
+ session_->connection()->SendPing(); |
+ EXPECT_FALSE(session_->connection()->connected()); |
+ |
+ EXPECT_TRUE(socket_data.AllReadDataConsumed()); |
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed()); |
} |
} // namespace |