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[] = { |