#include "net/quic/quic_ack_notifier.h"
#include "net/quic/quic_connection.h"
+#include "net/quic/quic_flags.h"
#include "net/quic/quic_utils.h"
#include "net/quic/quic_write_blocked_list.h"
#include "net/quic/spdy_utils.h"
+#include "net/quic/test_tools/quic_config_peer.h"
+#include "net/quic/test_tools/quic_flow_controller_peer.h"
#include "net/quic/test_tools/quic_session_peer.h"
#include "net/quic/test_tools/quic_test_utils.h"
#include "net/quic/test_tools/reliable_quic_stream_peer.h"
using base::StringPiece;
using std::min;
-using testing::_;
using testing::CreateFunctor;
using testing::InSequence;
using testing::Invoke;
using testing::SaveArg;
using testing::StrictMock;
using testing::WithArgs;
+using testing::_;
namespace net {
namespace test {
class ReliableQuicStreamTest : public ::testing::TestWithParam<bool> {
public:
- ReliableQuicStreamTest() {
+ ReliableQuicStreamTest()
+ : initial_flow_control_window_bytes_(kMaxPacketSize),
+ zero_(QuicTime::Delta::Zero()),
+ supported_versions_(QuicSupportedVersions()) {
headers_[":host"] = "www.google.com";
headers_[":path"] = "/index.hml";
headers_[":scheme"] = "https";
"JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo ";
}
+ void set_supported_versions(const QuicVersionVector& versions) {
+ supported_versions_ = versions;
+ }
+
void Initialize(bool stream_should_process_data) {
- connection_ = new StrictMock<MockConnection>(kIsServer);
+ connection_ =
+ new StrictMock<MockConnection>(kIsServer, supported_versions_);
session_.reset(new StrictMock<MockSession>(connection_));
+
+ // New streams rely on having the peer's flow control receive window
+ // negotiated in the config.
+ QuicConfigPeer::SetReceivedInitialFlowControlWindow(
+ session_->config(), initial_flow_control_window_bytes_);
+
stream_.reset(new TestStream(kStreamId, session_.get(),
stream_should_process_data));
stream2_.reset(new TestStream(kStreamId + 2, session_.get(),
bool fin_sent() { return ReliableQuicStreamPeer::FinSent(stream_.get()); }
bool rst_sent() { return ReliableQuicStreamPeer::RstSent(stream_.get()); }
+ void set_initial_flow_control_window_bytes(uint32 val) {
+ initial_flow_control_window_bytes_ = val;
+ }
+
protected:
MockConnection* connection_;
scoped_ptr<MockSession> session_;
scoped_ptr<TestStream> stream2_;
SpdyHeaderBlock headers_;
QuicWriteBlockedList* write_blocked_list_;
+ uint32 initial_flow_control_window_bytes_;
+ QuicTime::Delta zero_;
+ QuicVersionVector supported_versions_;
};
TEST_F(ReliableQuicStreamTest, WriteAllData) {
EXPECT_TRUE(rst_sent());
}
+TEST_F(ReliableQuicStreamTest, StreamFlowControlMultipleWindowUpdates) {
+ ValueRestore<bool> old_flag(&FLAGS_enable_quic_stream_flow_control_2, true);
+ set_initial_flow_control_window_bytes(1000);
+
+ Initialize(kShouldProcessData);
+
+ // If we receive multiple WINDOW_UPDATES (potentially out of order), then we
+ // want to make sure we latch the largest offset we see.
+
+ // Initially should be default.
+ EXPECT_EQ(initial_flow_control_window_bytes_,
+ QuicFlowControllerPeer::SendWindowOffset(
+ stream_.get()->flow_controller()));
+
+ // Check a single WINDOW_UPDATE results in correct offset.
+ QuicWindowUpdateFrame window_update_1(stream_->id(), 1234);
+ stream_->OnWindowUpdateFrame(window_update_1);
+ EXPECT_EQ(window_update_1.byte_offset,
+ QuicFlowControllerPeer::SendWindowOffset(
+ stream_.get()->flow_controller()));
+
+ // Now send a few more WINDOW_UPDATES and make sure that only the largest is
+ // remembered.
+ QuicWindowUpdateFrame window_update_2(stream_->id(), 1);
+ QuicWindowUpdateFrame window_update_3(stream_->id(), 9999);
+ QuicWindowUpdateFrame window_update_4(stream_->id(), 5678);
+ stream_->OnWindowUpdateFrame(window_update_2);
+ stream_->OnWindowUpdateFrame(window_update_3);
+ stream_->OnWindowUpdateFrame(window_update_4);
+ EXPECT_EQ(window_update_3.byte_offset,
+ QuicFlowControllerPeer::SendWindowOffset(
+ stream_.get()->flow_controller()));
+}
+
+TEST_F(ReliableQuicStreamTest, StreamFlowControlShouldNotBlockInLessThanQ017) {
+ // TODO(rjshade): Remove this test when we no longer have any versions <
+ // QUIC_VERSION_17.
+ ValueRestore<bool> old_flag(&FLAGS_enable_quic_stream_flow_control_2, true);
+
+ // Make sure we are using a version which does not support flow control.
+ QuicVersion kTestQuicVersions[] = {QUIC_VERSION_16};
+ QuicVersionVector versions;
+ for (size_t i = 0; i < arraysize(kTestQuicVersions); ++i) {
+ versions.push_back(kTestQuicVersions[i]);
+ }
+ set_supported_versions(versions);
+
+ // Peer is not talking QUIC_VERSION_17 so assumes that it can send a zero
+ // length flow control receive window with no consequences.
+ set_initial_flow_control_window_bytes(0);
+
+ Initialize(kShouldProcessData);
+
+ // The stream should _not_ be flow control blocked, because we are not talking
+ // a version which has flow control enabled.
+ EXPECT_FALSE(stream_->flow_controller()->IsBlocked());
+}
+
void SaveProxyAckNotifierDelegate(
scoped_refptr<QuicAckNotifier::DelegateInterface>* delegate_out,
QuicAckNotifier::DelegateInterface* delegate) {
*delegate_out = delegate;
}
+
TEST_F(ReliableQuicStreamTest, WriteOrBufferDataWithQuicAckNotifier) {
Initialize(kShouldProcessData);
const int kSecondWriteSize = 50;
const int kLastWriteSize = kDataSize - kFirstWriteSize - kSecondWriteSize;
+ // Set a large flow control send window so this doesn't interfere with test.
+ stream_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1);
+ if (FLAGS_enable_quic_connection_flow_control) {
+ connection_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1);
+ }
+
scoped_refptr<QuicAckNotifier::DelegateInterface> proxy_delegate;
EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(DoAll(
// There were two writes, so OnAckNotification is not propagated
// until the third Ack arrives.
- proxy_delegate->OnAckNotification(1, 2, 3, 4);
- proxy_delegate->OnAckNotification(10, 20, 30, 40);
+ proxy_delegate->OnAckNotification(1, 2, 3, 4, zero_);
+ proxy_delegate->OnAckNotification(10, 20, 30, 40, zero_);
// The arguments to delegate->OnAckNotification are the sum of the
// arguments to proxy_delegate OnAckNotification calls.
- EXPECT_CALL(*delegate, OnAckNotification(111, 222, 333, 444));
- proxy_delegate->OnAckNotification(100, 200, 300, 400);
+ EXPECT_CALL(*delegate, OnAckNotification(111, 222, 333, 444, zero_));
+ proxy_delegate->OnAckNotification(100, 200, 300, 400, zero_);
}
// Verify delegate behavior when packets are acked before the
const int kInitialWriteSize = 100;
+ // Set a large flow control send window so this doesn't interfere with test.
+ stream_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1);
+ if (FLAGS_enable_quic_connection_flow_control) {
+ connection_->flow_controller()->UpdateSendWindowOffset(kDataSize + 1);
+ }
+
scoped_refptr<QuicAckNotifier::DelegateInterface> proxy_delegate;
EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(DoAll(
EXPECT_TRUE(write_blocked_list_->HasWriteBlockedStreams());
// Handle the ack of the first write.
- proxy_delegate->OnAckNotification(1, 2, 3, 4);
+ proxy_delegate->OnAckNotification(1, 2, 3, 4, zero_);
proxy_delegate = NULL;
EXPECT_CALL(*session_, WritevData(kStreamId, _, _, _, _)).WillOnce(DoAll(
stream_->OnCanWrite();
// Handle the ack for the second write.
- EXPECT_CALL(*delegate, OnAckNotification(101, 202, 303, 404));
- proxy_delegate->OnAckNotification(100, 200, 300, 400);
+ EXPECT_CALL(*delegate, OnAckNotification(101, 202, 303, 404, zero_));
+ proxy_delegate->OnAckNotification(100, 200, 300, 400, zero_);
}
// Verify delegate behavior when WriteOrBufferData does not buffer.
EXPECT_FALSE(write_blocked_list_->HasWriteBlockedStreams());
// Handle the ack.
- EXPECT_CALL(*delegate, OnAckNotification(1, 2, 3, 4));
- proxy_delegate->OnAckNotification(1, 2, 3, 4);
+ EXPECT_CALL(*delegate, OnAckNotification(1, 2, 3, 4, zero_));
+ proxy_delegate->OnAckNotification(1, 2, 3, 4, zero_);
}
// Verify delegate behavior when WriteOrBufferData buffers all the data.
stream_->OnCanWrite();
// Handle the ack.
- EXPECT_CALL(*delegate, OnAckNotification(1, 2, 3, 4));
- proxy_delegate->OnAckNotification(1, 2, 3, 4);
+ EXPECT_CALL(*delegate, OnAckNotification(1, 2, 3, 4, zero_));
+ proxy_delegate->OnAckNotification(1, 2, 3, 4, zero_);
}
// Verify delegate behavior when WriteOrBufferData when the FIN is
stream_->OnCanWrite();
// Handle the acks.
- proxy_delegate->OnAckNotification(1, 2, 3, 4);
- EXPECT_CALL(*delegate, OnAckNotification(11, 22, 33, 44));
- proxy_delegate->OnAckNotification(10, 20, 30, 40);
+ proxy_delegate->OnAckNotification(1, 2, 3, 4, zero_);
+ EXPECT_CALL(*delegate, OnAckNotification(11, 22, 33, 44, zero_));
+ proxy_delegate->OnAckNotification(10, 20, 30, 40, zero_);
}
} // namespace