Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(323)

Unified Diff: net/quic/quic_stream_factory_test.cc

Issue 1327923002: Migrates QUIC sessions to a new network when old network is (about to be) disconnected. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@home
Patch Set: Naming fixes. Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: net/quic/quic_stream_factory_test.cc
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index c1390a435c121e201befda6239225ff45d48dfad..edd272f57dccc860149e7aa26b9f5bd0e0050c39 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -116,6 +116,65 @@ class MockQuicServerInfoFactory : public QuicServerInfoFactory {
}
};
+class MockNetworkChangeNotifier : public NetworkChangeNotifier {
+ public:
+ MockNetworkChangeNotifier() : force_network_handles_supported_(false) {}
+
+ ConnectionType GetCurrentConnectionType() const override {
+ return CONNECTION_UNKNOWN;
+ }
+
+ void ForceNetworkHandlesSupported() {
+ force_network_handles_supported_ = true;
+ }
+
+ bool AreNetworkHandlesCurrentlySupported() const override {
+ return force_network_handles_supported_;
+ }
+
+ void SetConnectedNetworksList(NetworkList network_list) {
+ connected_networks_ = network_list;
+ }
+
+ void GetCurrentConnectedNetworks(NetworkList* network_list) const override {
+ network_list->clear();
+ *network_list = connected_networks_;
+ }
+
+ private:
+ bool force_network_handles_supported_;
+ NetworkChangeNotifier::NetworkList connected_networks_;
+};
+
+// Class to replace existing NetworkChangeNotifier singleton with a
+// MockNetworkChangeNotifier for a test. To use, simply create a
+// ScopedMockNetworkChangeNotifier object in the test.
+class ScopedMockNetworkChangeNotifier {
+ public:
+ ScopedMockNetworkChangeNotifier()
+ : mock_network_change_notifier_(nullptr),
+ disable_network_change_notifier_for_tests_(nullptr) {
+ // Disable existing NetworkChangeNotifier first, then create mock.
+ disable_network_change_notifier_for_tests_ =
+ new NetworkChangeNotifier::DisableForTest();
+ mock_network_change_notifier_ = new MockNetworkChangeNotifier();
Ryan Hamilton 2015/12/18 22:00:19 I think you can initialize these in the initialize
Jana 2015/12/21 23:10:19 Done.
+ }
+
+ ~ScopedMockNetworkChangeNotifier() {
+ delete mock_network_change_notifier_;
+ delete disable_network_change_notifier_for_tests_;
Ryan Hamilton 2015/12/18 22:00:19 Can you use a scoped_ptr<> instead of needing to e
Jana 2015/12/21 23:10:19 Done.
+ }
+
+ MockNetworkChangeNotifier* mock_network_change_notifier() {
+ return mock_network_change_notifier_;
+ }
+
+ private:
+ MockNetworkChangeNotifier* mock_network_change_notifier_;
+ NetworkChangeNotifier::DisableForTest*
+ disable_network_change_notifier_for_tests_;
+};
+
class QuicStreamFactoryTest : public ::testing::TestWithParam<TestParams> {
protected:
QuicStreamFactoryTest()
@@ -148,7 +207,8 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<TestParams> {
delay_tcp_race_(false),
store_server_configs_in_properties_(false),
close_sessions_on_ip_change_(false),
- idle_connection_timeout_seconds_(kIdleConnectionTimeoutSeconds) {
+ idle_connection_timeout_seconds_(kIdleConnectionTimeoutSeconds),
+ migrate_sessions_on_network_change_(false) {
clock_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
}
@@ -169,7 +229,7 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<TestParams> {
threshold_public_resets_post_handshake_, receive_buffer_size_,
delay_tcp_race_, store_server_configs_in_properties_,
close_sessions_on_ip_change_, idle_connection_timeout_seconds_,
- QuicTagVector()));
+ migrate_sessions_on_network_change_, QuicTagVector()));
factory_->set_require_confirmation(false);
factory_->set_quic_server_info_factory(new MockQuicServerInfoFactory());
}
@@ -274,6 +334,16 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<TestParams> {
base::MessageLoop::current()->RunUntilIdle();
}
+ void NotifySpecificNetworkChange(
+ NetworkChangeNotifier::NetworkChangeType type,
+ NetworkChangeNotifier::NetworkHandle network) {
+ NetworkChangeNotifier::NotifyObserversOfSpecificNetworkChangeForTests(
+ type, network);
+ // For thread safety, the NCN queues tasks to do the actual notifications,
Ryan Hamilton 2015/12/18 22:00:19 I'd remove the first part of this (about thread sa
Jana 2015/12/21 23:10:19 I'm following the same pattern as is done with del
+ // so we need to spin the message loop so the notification is delivered.
+ base::MessageLoop::current()->RunUntilIdle();
+ }
+
MockHostResolver host_resolver_;
DeterministicMockClientSocketFactory socket_factory_;
MockCryptoClientStreamFactory crypto_client_stream_factory_;
@@ -311,6 +381,7 @@ class QuicStreamFactoryTest : public ::testing::TestWithParam<TestParams> {
bool store_server_configs_in_properties_;
bool close_sessions_on_ip_change_;
int idle_connection_timeout_seconds_;
+ bool migrate_sessions_on_network_change_;
};
INSTANTIATE_TEST_CASE_P(Version,
@@ -1293,6 +1364,104 @@ TEST_P(QuicStreamFactoryTest, OnIPAddressChanged) {
EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
}
+TEST_P(QuicStreamFactoryTest, OnNetworkChange) {
Ryan Hamilton 2015/12/18 22:00:19 Does this test all of the various combinations? Ac
Jana 2015/12/21 23:10:19 No it doesn't. I had meant to add them before send
+ ScopedMockNetworkChangeNotifier scoped_mock_ncn;
+ MockNetworkChangeNotifier* mock_ncn =
+ scoped_mock_ncn.mock_network_change_notifier();
+ mock_ncn->ForceNetworkHandlesSupported();
+ NetworkChangeNotifier::NetworkList connected_networks = {1, 2};
+ mock_ncn->SetConnectedNetworksList(connected_networks);
+
+ migrate_sessions_on_network_change_ = true;
+ Initialize();
+
+ // Set up first socket data provider
+ MockRead reads[] = {
+ MockRead(ASYNC, OK, 0) // EOF
+ };
+
+ DeterministicSocketData socket_data(reads, arraysize(reads), nullptr, 0);
+ socket_data.StopAfter(1);
+ socket_factory_.AddSocketDataProvider(&socket_data);
+
+ // Set up second socket data provider that is used after migration.
+ MockRead reads1[] = {
+ MockRead(ASYNC, OK, 0) // EOF
+ };
+ scoped_ptr<QuicEncryptedPacket> ping(
+ maker_.MakePingPacket(1, /*include_version=*/true));
+ MockWrite writes1[] = {
+ MockWrite(ASYNC, ping->data(), ping->length(), 1),
+ };
+ DeterministicSocketData socket_data1(reads1, arraysize(reads1), writes1,
+ arraysize(writes1));
+ socket_data1.StopAfter(1);
+ socket_factory_.AddSocketDataProvider(&socket_data1);
+
+ // Create request and QuicHttpStream.
+ QuicStreamRequest request(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
+
+ EXPECT_EQ(OK, callback_.WaitForResult());
+ scoped_ptr<QuicHttpStream> stream = request.ReleaseStream();
+ EXPECT_TRUE(stream.get());
+
+ // Cause QUIC stream to be created.
+ HttpRequestInfo request_info;
+ EXPECT_EQ(OK, stream->InitializeStream(&request_info, DEFAULT_PRIORITY,
+ net_log_, CompletionCallback()));
+
+ // Ensure that session is alive and active.
+ QuicChromiumClientSession* session =
+ QuicStreamFactoryPeer::GetActiveSession(factory_.get(), host_port_pair_);
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_TRUE(HasActiveSession(host_port_pair_));
+
+ // Cause connection migration to happen. This should cause a PING frame
+ // to be emitted.
+ NotifySpecificNetworkChange(NetworkChangeNotifier::SOON_TO_DISCONNECT, 1);
+
+ // The session should now be marked as going away. Ensure that
+ // while it is still alive, it is no longer active.
+ EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+ EXPECT_FALSE(HasActiveSession(host_port_pair_));
+ EXPECT_EQ(1u, session->GetNumActiveStreams());
+
+ // Create a new request for the same destination and verify that a
+ // new session is created.
+ MockRead reads2[] = {
+ MockRead(ASYNC, OK, 0) // EOF
+ };
+ DeterministicSocketData socket_data2(reads2, arraysize(reads2), nullptr, 0);
+ socket_data2.StopAfter(1);
+ socket_factory_.AddSocketDataProvider(&socket_data2);
+ QuicStreamRequest request2(factory_.get());
+ EXPECT_EQ(ERR_IO_PENDING,
+ request2.Request(host_port_pair_, privacy_mode_,
+ /*cert_verify_flags=*/0, host_port_pair_.host(),
+ "GET", net_log_, callback_.callback()));
+ EXPECT_EQ(OK, callback_.WaitForResult());
+ scoped_ptr<QuicHttpStream> stream2 = request2.ReleaseStream();
+ EXPECT_TRUE(stream2.get());
+
+ EXPECT_TRUE(
+ QuicStreamFactoryPeer::HasActiveSession(factory_.get(), host_port_pair_));
+ EXPECT_NE(session, QuicStreamFactoryPeer::GetActiveSession(factory_.get(),
+ host_port_pair_));
+ EXPECT_EQ(true,
+ QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session));
+
+ EXPECT_TRUE(socket_data.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data1.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data1.AllWriteDataConsumed());
+ EXPECT_TRUE(socket_data2.AllReadDataConsumed());
+ EXPECT_TRUE(socket_data2.AllWriteDataConsumed());
+}
+
TEST_P(QuicStreamFactoryTest, OnSSLConfigChanged) {
Initialize();
MockRead reads[] = {

Powered by Google App Engine
This is Rietveld 408576698