| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/tools/quic/quic_server_session.h" |
| |
| #include "net/quic/crypto/quic_crypto_server_config.h" |
| #include "net/quic/crypto/quic_random.h" |
| #include "net/quic/proto/cached_network_parameters.pb.h" |
| #include "net/quic/quic_connection.h" |
| #include "net/quic/quic_crypto_server_stream.h" |
| #include "net/quic/quic_flags.h" |
| #include "net/quic/quic_utils.h" |
| #include "net/quic/test_tools/crypto_test_utils.h" |
| #include "net/quic/test_tools/quic_config_peer.h" |
| #include "net/quic/test_tools/quic_connection_peer.h" |
| #include "net/quic/test_tools/quic_sent_packet_manager_peer.h" |
| #include "net/quic/test_tools/quic_session_peer.h" |
| #include "net/quic/test_tools/quic_spdy_session_peer.h" |
| #include "net/quic/test_tools/quic_spdy_stream_peer.h" |
| #include "net/quic/test_tools/quic_sustained_bandwidth_recorder_peer.h" |
| #include "net/quic/test_tools/quic_test_utils.h" |
| #include "net/test/gtest_util.h" |
| #include "net/tools/quic/quic_spdy_server_stream.h" |
| #include "net/tools/quic/test_tools/mock_quic_server_session_visitor.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using __gnu_cxx::vector; |
| using net::test::CryptoTestUtils; |
| using net::test::MockConnection; |
| using net::test::MockConnectionHelper; |
| using net::test::QuicConfigPeer; |
| using net::test::QuicConnectionPeer; |
| using net::test::QuicSpdyStreamPeer; |
| using net::test::QuicSentPacketManagerPeer; |
| using net::test::QuicSessionPeer; |
| using net::test::QuicSpdySessionPeer; |
| using net::test::QuicSustainedBandwidthRecorderPeer; |
| using net::test::SupportedVersions; |
| using net::test::ValueRestore; |
| using net::test::kClientDataStreamId1; |
| using net::test::kClientDataStreamId2; |
| using net::test::kClientDataStreamId3; |
| using net::test::kInitialSessionFlowControlWindowForTest; |
| using net::test::kInitialStreamFlowControlWindowForTest; |
| using std::string; |
| using testing::StrictMock; |
| using testing::_; |
| |
| namespace net { |
| namespace tools { |
| namespace test { |
| |
| class QuicServerSessionPeer { |
| public: |
| static ReliableQuicStream* GetOrCreateDynamicStream(QuicServerSession* s, |
| QuicStreamId id) { |
| return s->GetOrCreateDynamicStream(id); |
| } |
| static void SetCryptoStream(QuicServerSession* s, |
| QuicCryptoServerStream* crypto_stream) { |
| s->crypto_stream_.reset(crypto_stream); |
| s->static_streams()[kCryptoStreamId] = crypto_stream; |
| } |
| static bool IsBandwidthResumptionEnabled(QuicServerSession* s) { |
| return s->bandwidth_resumption_enabled_; |
| } |
| }; |
| |
| namespace { |
| |
| const size_t kMaxStreamsForTest = 10; |
| |
| class QuicServerSessionTest : public ::testing::TestWithParam<QuicVersion> { |
| protected: |
| QuicServerSessionTest() |
| : crypto_config_(QuicCryptoServerConfig::TESTING, |
| QuicRandom::GetInstance(), |
| CryptoTestUtils::ProofSourceForTesting()) { |
| config_.SetMaxStreamsPerConnection(kMaxStreamsForTest, |
| kMaxStreamsForTest); |
| config_.SetInitialStreamFlowControlWindowToSend( |
| kInitialStreamFlowControlWindowForTest); |
| config_.SetInitialSessionFlowControlWindowToSend( |
| kInitialSessionFlowControlWindowForTest); |
| |
| connection_ = new StrictMock<MockConnection>( |
| &helper_, Perspective::IS_SERVER, SupportedVersions(GetParam())); |
| session_.reset( |
| new QuicServerSession(config_, connection_, &owner_, &crypto_config_)); |
| MockClock clock; |
| handshake_message_.reset(crypto_config_.AddDefaultConfig( |
| QuicRandom::GetInstance(), &clock, |
| QuicCryptoServerConfig::ConfigOptions())); |
| session_->Initialize(); |
| visitor_ = QuicConnectionPeer::GetVisitor(connection_); |
| } |
| |
| StrictMock<MockQuicServerSessionVisitor> owner_; |
| MockConnectionHelper helper_; |
| StrictMock<MockConnection>* connection_; |
| QuicConfig config_; |
| QuicCryptoServerConfig crypto_config_; |
| scoped_ptr<QuicServerSession> session_; |
| scoped_ptr<CryptoHandshakeMessage> handshake_message_; |
| QuicConnectionVisitorInterface* visitor_; |
| }; |
| |
| // Compares CachedNetworkParameters. |
| MATCHER_P(EqualsProto, network_params, "") { |
| CachedNetworkParameters reference(network_params); |
| return (arg->bandwidth_estimate_bytes_per_second() == |
| reference.bandwidth_estimate_bytes_per_second() && |
| arg->bandwidth_estimate_bytes_per_second() == |
| reference.bandwidth_estimate_bytes_per_second() && |
| arg->max_bandwidth_estimate_bytes_per_second() == |
| reference.max_bandwidth_estimate_bytes_per_second() && |
| arg->max_bandwidth_timestamp_seconds() == |
| reference.max_bandwidth_timestamp_seconds() && |
| arg->min_rtt_ms() == reference.min_rtt_ms() && |
| arg->previous_connection_state() == |
| reference.previous_connection_state()); |
| } |
| |
| INSTANTIATE_TEST_CASE_P(Tests, QuicServerSessionTest, |
| ::testing::ValuesIn(QuicSupportedVersions())); |
| |
| TEST_P(QuicServerSessionTest, CloseStreamDueToReset) { |
| // Open a stream, then reset it. |
| // Send two bytes of payload to open it. |
| QuicStreamFrame data1(kClientDataStreamId1, false, 0, StringPiece("HT")); |
| session_->OnStreamFrame(data1); |
| EXPECT_EQ(1u, session_->GetNumOpenStreams()); |
| |
| // Send a reset (and expect the peer to send a RST in response). |
| QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM, |
| 0); |
| EXPECT_CALL(*connection_, |
| SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0)); |
| visitor_->OnRstStream(rst1); |
| EXPECT_EQ(0u, session_->GetNumOpenStreams()); |
| |
| // Send the same two bytes of payload in a new packet. |
| visitor_->OnStreamFrame(data1); |
| |
| // The stream should not be re-opened. |
| EXPECT_EQ(0u, session_->GetNumOpenStreams()); |
| EXPECT_TRUE(connection_->connected()); |
| } |
| |
| TEST_P(QuicServerSessionTest, NeverOpenStreamDueToReset) { |
| // Send a reset (and expect the peer to send a RST in response). |
| QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM, |
| 0); |
| EXPECT_CALL(*connection_, |
| SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0)); |
| visitor_->OnRstStream(rst1); |
| EXPECT_EQ(0u, session_->GetNumOpenStreams()); |
| |
| // Send two bytes of payload. |
| QuicStreamFrame data1(kClientDataStreamId1, false, 0, StringPiece("HT")); |
| visitor_->OnStreamFrame(data1); |
| |
| // The stream should never be opened, now that the reset is received. |
| EXPECT_EQ(0u, session_->GetNumOpenStreams()); |
| EXPECT_TRUE(connection_->connected()); |
| } |
| |
| TEST_P(QuicServerSessionTest, AcceptClosedStream) { |
| // Send (empty) compressed headers followed by two bytes of data. |
| QuicStreamFrame frame1(kClientDataStreamId1, false, 0, |
| StringPiece("\1\0\0\0\0\0\0\0HT")); |
| QuicStreamFrame frame2(kClientDataStreamId2, false, 0, |
| StringPiece("\2\0\0\0\0\0\0\0HT")); |
| visitor_->OnStreamFrame(frame1); |
| visitor_->OnStreamFrame(frame2); |
| EXPECT_EQ(2u, session_->GetNumOpenStreams()); |
| |
| // Send a reset (and expect the peer to send a RST in response). |
| QuicRstStreamFrame rst(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM, 0); |
| EXPECT_CALL(*connection_, |
| SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0)); |
| visitor_->OnRstStream(rst); |
| |
| // If we were tracking, we'd probably want to reject this because it's data |
| // past the reset point of stream 3. As it's a closed stream we just drop the |
| // data on the floor, but accept the packet because it has data for stream 5. |
| QuicStreamFrame frame3(kClientDataStreamId1, false, 2, StringPiece("TP")); |
| QuicStreamFrame frame4(kClientDataStreamId2, false, 2, StringPiece("TP")); |
| visitor_->OnStreamFrame(frame3); |
| visitor_->OnStreamFrame(frame4); |
| // The stream should never be opened, now that the reset is received. |
| EXPECT_EQ(1u, session_->GetNumOpenStreams()); |
| EXPECT_TRUE(connection_->connected()); |
| } |
| |
| TEST_P(QuicServerSessionTest, MaxOpenStreams) { |
| // Test that the server refuses if a client attempts to open too many data |
| // streams. The server accepts slightly more than the negotiated stream limit |
| // to deal with rare cases where a client FIN/RST is lost. |
| |
| // The slightly increased stream limit is set during config negotiation. It |
| // is either an increase of 10 over negotiated limit, or a fixed percentage |
| // scaling, whichever is larger. Test both before continuing. |
| EXPECT_EQ(kMaxStreamsForTest, session_->get_max_open_streams()); |
| session_->OnConfigNegotiated(); |
| EXPECT_LT(kMaxStreamsMultiplier * kMaxStreamsForTest, |
| kMaxStreamsForTest + kMaxStreamsMinimumIncrement); |
| EXPECT_EQ(kMaxStreamsForTest + kMaxStreamsMinimumIncrement, |
| session_->get_max_open_streams()); |
| EXPECT_EQ(0u, session_->GetNumOpenStreams()); |
| QuicStreamId stream_id = kClientDataStreamId1; |
| // Open the max configured number of streams, should be no problem. |
| for (size_t i = 0; i < kMaxStreamsForTest; ++i) { |
| EXPECT_TRUE(QuicServerSessionPeer::GetOrCreateDynamicStream(session_.get(), |
| stream_id)); |
| stream_id += 2; |
| } |
| |
| // Open more streams: server should accept slightly more than the limit. |
| for (size_t i = 0; i < kMaxStreamsMinimumIncrement; ++i) { |
| EXPECT_TRUE(QuicServerSessionPeer::GetOrCreateDynamicStream(session_.get(), |
| stream_id)); |
| stream_id += 2; |
| } |
| |
| // Now violate the server's internal stream limit. |
| stream_id += 2; |
| if (connection_->version() <= QUIC_VERSION_27) { |
| EXPECT_CALL(*connection_, SendConnectionClose(QUIC_TOO_MANY_OPEN_STREAMS)); |
| EXPECT_CALL(*connection_, SendRstStream(_, _, _)).Times(0); |
| } else { |
| EXPECT_CALL(*connection_, SendConnectionClose(_)).Times(0); |
| EXPECT_CALL(*connection_, SendRstStream(stream_id, QUIC_REFUSED_STREAM, 0)); |
| } |
| // Even if the connection remains open, the stream creation should fail. |
| EXPECT_FALSE(QuicServerSessionPeer::GetOrCreateDynamicStream(session_.get(), |
| stream_id)); |
| } |
| |
| TEST_P(QuicServerSessionTest, MaxAvailableStreams) { |
| // Test that the server closes the connection if a client makes too many data |
| // streams available. The server accepts slightly more than the negotiated |
| // stream limit to deal with rare cases where a client FIN/RST is lost. |
| |
| // The slightly increased stream limit is set during config negotiation. |
| EXPECT_EQ(kMaxStreamsForTest, session_->get_max_open_streams()); |
| session_->OnConfigNegotiated(); |
| const size_t kAvailableStreamLimit = session_->get_max_available_streams(); |
| EXPECT_EQ(session_->get_max_open_streams() * kMaxAvailableStreamsMultiplier, |
| session_->get_max_available_streams()); |
| // The protocol specification requires that there can be at least 10 times |
| // as many available streams as the connection's maximum open streams. |
| EXPECT_LE(10 * kMaxStreamsForTest, kAvailableStreamLimit); |
| |
| EXPECT_EQ(0u, session_->GetNumOpenStreams()); |
| EXPECT_TRUE(QuicServerSessionPeer::GetOrCreateDynamicStream( |
| session_.get(), kClientDataStreamId1)); |
| |
| // Establish available streams up to the server's limit. |
| const int kLimitingStreamId = |
| FLAGS_allow_many_available_streams |
| ? kClientDataStreamId1 + (kAvailableStreamLimit)*2 + 2 |
| : kClientDataStreamId1 + (session_->get_max_open_streams() - 1) * 2; |
| EXPECT_TRUE(QuicServerSessionPeer::GetOrCreateDynamicStream( |
| session_.get(), kLimitingStreamId)); |
| |
| // A further available stream will result in connection close. |
| if (FLAGS_allow_many_available_streams) { |
| EXPECT_CALL(*connection_, |
| SendConnectionClose(QUIC_TOO_MANY_AVAILABLE_STREAMS)); |
| } else { |
| EXPECT_CALL(*connection_, SendConnectionClose(QUIC_TOO_MANY_OPEN_STREAMS)); |
| } |
| // This forces stream kLimitingStreamId + 2 to become available, which |
| // violates the quota. |
| EXPECT_FALSE(QuicServerSessionPeer::GetOrCreateDynamicStream( |
| session_.get(), kLimitingStreamId + 4)); |
| } |
| |
| TEST_P(QuicServerSessionTest, GetEvenIncomingError) { |
| // Incoming streams on the server session must be odd. |
| EXPECT_CALL(*connection_, SendConnectionClose(QUIC_INVALID_STREAM_ID)); |
| EXPECT_EQ(nullptr, |
| QuicServerSessionPeer::GetOrCreateDynamicStream(session_.get(), 4)); |
| } |
| |
| TEST_P(QuicServerSessionTest, GetStreamDisconnected) { |
| // Don't create new streams if the connection is disconnected. |
| QuicConnectionPeer::CloseConnection(connection_); |
| EXPECT_DFATAL( |
| QuicServerSessionPeer::GetOrCreateDynamicStream(session_.get(), 5), |
| "ShouldCreateIncomingDynamicStream called when disconnected"); |
| } |
| |
| TEST_P(QuicServerSessionTest, SetFecProtectionFromConfig) { |
| ValueRestore<bool> old_flag(&FLAGS_enable_quic_fec, true); |
| |
| // Set received config to have FEC connection option. |
| QuicTagVector copt; |
| copt.push_back(kFHDR); |
| QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); |
| session_->OnConfigNegotiated(); |
| |
| // Verify that headers stream is always protected and data streams are |
| // optionally protected. |
| EXPECT_EQ(FEC_PROTECT_ALWAYS, QuicSpdySessionPeer::GetHeadersStream( |
| session_.get())->fec_policy()); |
| ReliableQuicStream* stream = QuicServerSessionPeer::GetOrCreateDynamicStream( |
| session_.get(), kClientDataStreamId1); |
| ASSERT_TRUE(stream); |
| EXPECT_EQ(FEC_PROTECT_OPTIONAL, stream->fec_policy()); |
| } |
| |
| class MockQuicCryptoServerStream : public QuicCryptoServerStream { |
| public: |
| explicit MockQuicCryptoServerStream( |
| const QuicCryptoServerConfig* crypto_config, QuicSession* session) |
| : QuicCryptoServerStream(crypto_config, session) {} |
| ~MockQuicCryptoServerStream() override {} |
| |
| MOCK_METHOD1(SendServerConfigUpdate, |
| void(const CachedNetworkParameters* cached_network_parameters)); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(MockQuicCryptoServerStream); |
| }; |
| |
| TEST_P(QuicServerSessionTest, BandwidthEstimates) { |
| // Test that bandwidth estimate updates are sent to the client, only when |
| // bandwidth resumption is enabled, the bandwidth estimate has changed |
| // sufficiently, enough time has passed, |
| // and we don't have any other data to write. |
| |
| // Client has sent kBWRE connection option to trigger bandwidth resumption. |
| QuicTagVector copt; |
| copt.push_back(kBWRE); |
| QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); |
| session_->OnConfigNegotiated(); |
| EXPECT_TRUE( |
| QuicServerSessionPeer::IsBandwidthResumptionEnabled(session_.get())); |
| |
| int32 bandwidth_estimate_kbytes_per_second = 123; |
| int32 max_bandwidth_estimate_kbytes_per_second = 134; |
| int32 max_bandwidth_estimate_timestamp = 1122334455; |
| const string serving_region = "not a real region"; |
| session_->set_serving_region(serving_region); |
| |
| MockQuicCryptoServerStream* crypto_stream = |
| new MockQuicCryptoServerStream(&crypto_config_, session_.get()); |
| QuicServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream); |
| |
| // Set some initial bandwidth values. |
| QuicSentPacketManager* sent_packet_manager = |
| QuicConnectionPeer::GetSentPacketManager(session_->connection()); |
| QuicSustainedBandwidthRecorder& bandwidth_recorder = |
| QuicSentPacketManagerPeer::GetBandwidthRecorder(sent_packet_manager); |
| // Seed an rtt measurement equal to the initial default rtt. |
| RttStats* rtt_stats = |
| QuicSentPacketManagerPeer::GetRttStats(sent_packet_manager); |
| rtt_stats->UpdateRtt(QuicTime::Delta::FromMicroseconds( |
| rtt_stats->initial_rtt_us()), QuicTime::Delta::Zero(), QuicTime::Zero()); |
| QuicSustainedBandwidthRecorderPeer::SetBandwidthEstimate( |
| &bandwidth_recorder, bandwidth_estimate_kbytes_per_second); |
| QuicSustainedBandwidthRecorderPeer::SetMaxBandwidthEstimate( |
| &bandwidth_recorder, max_bandwidth_estimate_kbytes_per_second, |
| max_bandwidth_estimate_timestamp); |
| // Queue up some pending data. |
| session_->MarkConnectionLevelWriteBlocked( |
| kCryptoStreamId, QuicWriteBlockedList::kHighestPriority); |
| EXPECT_TRUE(session_->HasDataToWrite()); |
| |
| // There will be no update sent yet - not enough time has passed. |
| QuicTime now = QuicTime::Zero(); |
| session_->OnCongestionWindowChange(now); |
| |
| // Bandwidth estimate has now changed sufficiently but not enough time has |
| // passed to send a Server Config Update. |
| bandwidth_estimate_kbytes_per_second = |
| bandwidth_estimate_kbytes_per_second * 1.6; |
| session_->OnCongestionWindowChange(now); |
| |
| // Bandwidth estimate has now changed sufficiently and enough time has passed, |
| // but not enough packets have been sent. |
| int64 srtt_ms = |
| sent_packet_manager->GetRttStats()->smoothed_rtt().ToMilliseconds(); |
| now = now.Add(QuicTime::Delta::FromMilliseconds( |
| kMinIntervalBetweenServerConfigUpdatesRTTs * srtt_ms)); |
| session_->OnCongestionWindowChange(now); |
| |
| // The connection no longer has pending data to be written. |
| session_->OnCanWrite(); |
| EXPECT_FALSE(session_->HasDataToWrite()); |
| session_->OnCongestionWindowChange(now); |
| |
| // Bandwidth estimate has now changed sufficiently, enough time has passed, |
| // and enough packets have been sent. |
| QuicConnectionPeer::SetPacketNumberOfLastSentPacket( |
| session_->connection(), kMinPacketsBetweenServerConfigUpdates); |
| |
| // Verify that the proto has exactly the values we expect. |
| CachedNetworkParameters expected_network_params; |
| expected_network_params.set_bandwidth_estimate_bytes_per_second( |
| bandwidth_recorder.BandwidthEstimate().ToBytesPerSecond()); |
| expected_network_params.set_max_bandwidth_estimate_bytes_per_second( |
| bandwidth_recorder.MaxBandwidthEstimate().ToBytesPerSecond()); |
| expected_network_params.set_max_bandwidth_timestamp_seconds( |
| bandwidth_recorder.MaxBandwidthTimestamp()); |
| expected_network_params.set_min_rtt_ms(session_->connection() |
| ->sent_packet_manager() |
| .GetRttStats() |
| ->min_rtt() |
| .ToMilliseconds()); |
| expected_network_params.set_previous_connection_state( |
| CachedNetworkParameters::CONGESTION_AVOIDANCE); |
| expected_network_params.set_timestamp( |
| session_->connection()->clock()->WallNow().ToUNIXSeconds()); |
| expected_network_params.set_serving_region(serving_region); |
| |
| EXPECT_CALL(*crypto_stream, |
| SendServerConfigUpdate(EqualsProto(expected_network_params))) |
| .Times(1); |
| EXPECT_CALL(*connection_, OnSendConnectionState(_)).Times(1); |
| session_->OnCongestionWindowChange(now); |
| } |
| |
| TEST_P(QuicServerSessionTest, BandwidthResumptionExperiment) { |
| // Test that if a client provides a CachedNetworkParameters with the same |
| // serving region as the current server, and which was made within an hour of |
| // now, that this data is passed down to the send algorithm. |
| |
| // Client has sent kBWRE connection option to trigger bandwidth resumption. |
| QuicTagVector copt; |
| copt.push_back(kBWRE); |
| QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); |
| |
| const string kTestServingRegion = "a serving region"; |
| session_->set_serving_region(kTestServingRegion); |
| |
| // Set the time to be one hour + one second from the 0 baseline. |
| connection_->AdvanceTime( |
| QuicTime::Delta::FromSeconds(kNumSecondsPerHour + 1)); |
| |
| QuicCryptoServerStream* crypto_stream = |
| static_cast<QuicCryptoServerStream*>( |
| QuicSessionPeer::GetCryptoStream(session_.get())); |
| |
| // No effect if no CachedNetworkParameters provided. |
| EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(0); |
| session_->OnConfigNegotiated(); |
| |
| // No effect if CachedNetworkParameters provided, but different serving |
| // regions. |
| CachedNetworkParameters cached_network_params; |
| cached_network_params.set_bandwidth_estimate_bytes_per_second(1); |
| cached_network_params.set_serving_region("different serving region"); |
| crypto_stream->set_previous_cached_network_params(cached_network_params); |
| EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(0); |
| session_->OnConfigNegotiated(); |
| |
| // Same serving region, but timestamp is too old, should have no effect. |
| cached_network_params.set_serving_region(kTestServingRegion); |
| cached_network_params.set_timestamp(0); |
| crypto_stream->set_previous_cached_network_params(cached_network_params); |
| EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(0); |
| session_->OnConfigNegotiated(); |
| |
| // Same serving region, and timestamp is recent: estimate is stored. |
| cached_network_params.set_timestamp( |
| connection_->clock()->WallNow().ToUNIXSeconds()); |
| crypto_stream->set_previous_cached_network_params(cached_network_params); |
| EXPECT_CALL(*connection_, ResumeConnectionState(_, _)).Times(1); |
| session_->OnConfigNegotiated(); |
| } |
| |
| TEST_P(QuicServerSessionTest, BandwidthMaxEnablesResumption) { |
| EXPECT_FALSE( |
| QuicServerSessionPeer::IsBandwidthResumptionEnabled(session_.get())); |
| |
| // Client has sent kBWMX connection option to trigger bandwidth resumption. |
| QuicTagVector copt; |
| copt.push_back(kBWMX); |
| QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt); |
| session_->OnConfigNegotiated(); |
| EXPECT_TRUE( |
| QuicServerSessionPeer::IsBandwidthResumptionEnabled(session_.get())); |
| } |
| |
| TEST_P(QuicServerSessionTest, NoBandwidthResumptionByDefault) { |
| EXPECT_FALSE( |
| QuicServerSessionPeer::IsBandwidthResumptionEnabled(session_.get())); |
| session_->OnConfigNegotiated(); |
| EXPECT_FALSE( |
| QuicServerSessionPeer::IsBandwidthResumptionEnabled(session_.get())); |
| } |
| |
| } // namespace |
| } // namespace test |
| } // namespace tools |
| } // namespace net |