Index: net/quic/quic_headers_stream_test.cc |
diff --git a/net/quic/quic_headers_stream_test.cc b/net/quic/quic_headers_stream_test.cc |
index 1dbc07e8f4b21dda64fb0a905a6d3ca87f2d39d5..728e897adb712d602206e36c2a4bf4d96ef22164 100644 |
--- a/net/quic/quic_headers_stream_test.cc |
+++ b/net/quic/quic_headers_stream_test.cc |
@@ -7,6 +7,7 @@ |
#include <string> |
#include "base/strings/string_number_conversions.h" |
+#include "net/quic/quic_bug_tracker.h" |
#include "net/quic/quic_utils.h" |
#include "net/quic/spdy_utils.h" |
#include "net/quic/test_tools/quic_connection_peer.h" |
@@ -26,6 +27,9 @@ using std::ostream; |
using std::string; |
using std::vector; |
using testing::ElementsAre; |
+using testing::_; |
+using testing::AtLeast; |
+using testing::HasSubstr; |
using testing::InSequence; |
using testing::Invoke; |
using testing::Return; |
@@ -114,6 +118,26 @@ class MockVisitor : public SpdyFramerVisitorInterface { |
MOCK_METHOD2(OnUnknownFrame, bool(SpdyStreamId stream_id, int frame_type)); |
}; |
+class ForceHolAckListener : public QuicAckListenerInterface { |
+ public: |
+ ForceHolAckListener() : total_acked_bytes_(0) {} |
+ |
+ void OnPacketAcked(int acked_bytes, QuicTime::Delta ack_delay_time) override { |
+ total_acked_bytes_ += acked_bytes; |
+ } |
+ |
+ void OnPacketRetransmitted(int retransmitted_bytes) override {} |
+ |
+ size_t total_acked_bytes() { return total_acked_bytes_; } |
+ |
+ private: |
+ ~ForceHolAckListener() override {} |
+ |
+ size_t total_acked_bytes_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(ForceHolAckListener); |
+}; |
+ |
// Run all tests with each version, perspective (client or server), |
// and relevant flag options (false or true) |
struct TestParams { |
@@ -171,10 +195,27 @@ class QuicHeadersStreamTest : public ::testing::TestWithParam<TestParams> { |
QuicConsumedData SaveIov(const QuicIOVector& data) { |
const iovec* iov = data.iov; |
int count = data.iov_count; |
+ int consumed = 0; |
for (int i = 0; i < count; ++i) { |
saved_data_.append(static_cast<char*>(iov[i].iov_base), iov[i].iov_len); |
+ consumed += iov[i].iov_len; |
} |
- return QuicConsumedData(saved_data_.length(), false); |
+ return QuicConsumedData(consumed, false); |
+ } |
+ |
+ QuicConsumedData SaveIovAndNotifyAckListener( |
+ const QuicIOVector& data, |
+ QuicAckListenerInterface* ack_listener) { |
+ QuicConsumedData result = SaveIov(data); |
+ if (ack_listener) { |
+ ack_listener->OnPacketAcked(result.bytes_consumed, |
+ QuicTime::Delta::Zero()); |
+ } |
+ return result; |
+ } |
+ |
+ void SavePayload(const char* data, size_t len) { |
+ saved_payloads_.append(data, len); |
} |
bool SaveHeaderData(const char* data, int len) { |
@@ -293,6 +334,7 @@ class QuicHeadersStreamTest : public ::testing::TestWithParam<TestParams> { |
string body_; |
string saved_data_; |
string saved_header_data_; |
+ string saved_payloads_; |
std::unique_ptr<SpdyFramer> framer_; |
StrictMock<MockVisitor> visitor_; |
std::unique_ptr<StrictMock<MockHpackDebugVisitor>> hpack_encoder_visitor_; |
@@ -455,9 +497,6 @@ TEST_P(QuicHeadersStreamTest, EmptyHeaderHOLBlockedTime) { |
} |
TEST_P(QuicHeadersStreamTest, NonEmptyHeaderHOLBlockedTime) { |
- if (!FLAGS_quic_measure_headers_hol_blocking_time) { |
- return; |
- } |
QuicStreamId stream_id; |
bool fin = true; |
QuicStreamFrame stream_frames[10]; |
@@ -550,8 +589,9 @@ TEST_P(QuicHeadersStreamTest, ProcessBadData) { |
} |
TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrame) { |
- SpdyDataIR data(2, ""); |
+ SpdyDataIR data(2, "ping"); |
SpdySerializedFrame frame(framer_->SerializeFrame(data)); |
+ |
EXPECT_CALL(*connection_, CloseConnection(QUIC_INVALID_HEADERS_STREAM_DATA, |
"SPDY DATA frame received.", _)) |
.WillOnce(InvokeWithoutArgs( |
@@ -561,6 +601,33 @@ TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrame) { |
headers_stream_->OnStreamFrame(stream_frame_); |
} |
+TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrameForceHolBlocking) { |
+ if (version() <= QUIC_VERSION_35) { |
+ return; |
+ } |
+ QuicSpdySessionPeer::SetForceHolBlocking(&session_, true); |
+ SpdyDataIR data(2, "ping"); |
+ SpdySerializedFrame frame(framer_->SerializeFrame(data)); |
+ EXPECT_CALL(session_, OnStreamFrameData(2, _, 4, false)); |
+ stream_frame_.data_buffer = frame.data(); |
+ stream_frame_.data_length = frame.size(); |
+ headers_stream_->OnStreamFrame(stream_frame_); |
+} |
+ |
+TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrameEmptyWithFin) { |
+ if (version() <= QUIC_VERSION_35) { |
+ return; |
+ } |
+ QuicSpdySessionPeer::SetForceHolBlocking(&session_, true); |
+ SpdyDataIR data(2, ""); |
+ data.set_fin(true); |
+ SpdySerializedFrame frame(framer_->SerializeFrame(data)); |
+ EXPECT_CALL(session_, OnStreamFrameData(2, _, 0, true)); |
+ stream_frame_.data_buffer = frame.data(); |
+ stream_frame_.data_length = frame.size(); |
+ headers_stream_->OnStreamFrame(stream_frame_); |
+} |
+ |
TEST_P(QuicHeadersStreamTest, ProcessSpdyRstStreamFrame) { |
SpdyRstStreamIR data(2, RST_STREAM_PROTOCOL_ERROR); |
SpdySerializedFrame frame(framer_->SerializeFrame(data)); |
@@ -781,6 +848,61 @@ TEST_P(QuicHeadersStreamTest, HpackEncoderDebugVisitor) { |
} |
} |
+TEST_P(QuicHeadersStreamTest, WritevStreamData) { |
+ QuicStreamId id = kClientDataStreamId1; |
+ QuicStreamOffset offset = 0; |
+ struct iovec iov; |
+ string data; |
+ |
+ // This test will issue a write that will require fragmenting into |
+ // multiple HTTP/2 DATA frames. |
+ const int kMinDataFrames = 4; |
+ const size_t data_len = |
+ SpdyConstants::GetFrameMaximumSize(HTTP2) * kMinDataFrames + 1024; |
+ // Set headers stream send window large enough for data written below. |
+ headers_stream_->flow_controller()->UpdateSendWindowOffset(data_len * 2 * 4); |
+ test::GenerateBody(&data, data_len); |
+ |
+ for (bool fin : {true, false}) { |
+ for (bool use_ack_listener : {true, false}) { |
+ scoped_refptr<ForceHolAckListener> ack_listener; |
+ if (use_ack_listener) { |
+ ack_listener = new ForceHolAckListener(); |
+ } |
+ EXPECT_CALL(session_, |
+ WritevData(headers_stream_, kHeadersStreamId, _, _, false, _)) |
+ .WillRepeatedly(WithArgs<2, 5>(Invoke( |
+ this, &QuicHeadersStreamTest::SaveIovAndNotifyAckListener))); |
+ |
+ QuicConsumedData consumed_data = headers_stream_->WritevStreamData( |
+ id, MakeIOVector(data, &iov), offset, fin, ack_listener.get()); |
+ |
+ EXPECT_EQ(consumed_data.bytes_consumed, data_len); |
+ EXPECT_EQ(consumed_data.fin_consumed, fin); |
+ // Now process the written data with the SPDY framer, and verify |
+ // that the original data is unchanged. |
+ EXPECT_CALL(visitor_, OnDataFrameHeader(id, _, _)) |
+ .Times(AtLeast(kMinDataFrames)); |
+ EXPECT_CALL(visitor_, OnStreamFrameData(id, _, _)) |
+ .WillRepeatedly(WithArgs<1, 2>( |
+ Invoke(this, &QuicHeadersStreamTest::SavePayload))); |
+ if (fin) { |
+ EXPECT_CALL(visitor_, OnStreamEnd(id)); |
+ } |
+ framer_->ProcessInput(saved_data_.data(), saved_data_.length()); |
+ EXPECT_EQ(saved_payloads_, data); |
+ |
+ if (use_ack_listener) { |
+ // Notice, acked bytes doesn't include extra bytes used by |
+ // HTTP/2 DATA frame headers. |
+ EXPECT_EQ(ack_listener->total_acked_bytes(), data_len); |
+ } |
+ saved_data_.clear(); |
+ saved_payloads_.clear(); |
+ } |
+ } |
+} |
+ |
} // namespace |
} // namespace test |
} // namespace net |