blob: b93e0eb430a6ebf3a2380fdd2680e29215fc7c46 [file] [log] [blame]
// Copyright (c) 2019 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 "quic/quic_transport/quic_transport_stream.h"
#include <memory>
#include "absl/memory/memory.h"
#include "absl/strings/string_view.h"
#include "quic/core/crypto/null_encrypter.h"
#include "quic/core/frames/quic_window_update_frame.h"
#include "quic/platform/api/quic_expect_bug.h"
#include "quic/platform/api/quic_test.h"
#include "quic/quic_transport/quic_transport_session_interface.h"
#include "quic/test_tools/quic_config_peer.h"
#include "quic/test_tools/quic_test_utils.h"
#include "quic/test_tools/quic_transport_test_tools.h"
namespace quic {
namespace test {
namespace {
using testing::_;
using testing::Return;
ParsedQuicVersionVector GetVersions() {
return {DefaultVersionForQuicTransport()};
}
class MockQuicTransportSessionInterface : public QuicTransportSessionInterface {
public:
MOCK_METHOD(bool, IsSessionReady, (), (const, override));
};
class QuicTransportStreamTest : public QuicTest {
public:
QuicTransportStreamTest()
: connection_(new MockQuicConnection(&helper_,
&alarm_factory_,
Perspective::IS_CLIENT,
GetVersions())),
session_(connection_) {
QuicEnableVersion(DefaultVersionForQuicTransport());
session_.Initialize();
connection_->SetEncrypter(
ENCRYPTION_FORWARD_SECURE,
std::make_unique<NullEncrypter>(connection_->perspective()));
stream_ = new QuicTransportStream(0, &session_, &interface_);
session_.ActivateStream(absl::WrapUnique(stream_));
auto visitor = std::make_unique<MockStreamVisitor>();
visitor_ = visitor.get();
stream_->SetVisitor(std::move(visitor));
}
void ReceiveStreamData(absl::string_view data, QuicStreamOffset offset) {
QuicStreamFrame frame(0, false, offset, data);
stream_->OnStreamFrame(frame);
}
protected:
MockAlarmFactory alarm_factory_;
MockQuicConnectionHelper helper_;
MockQuicConnection* connection_; // Owned by |session_|.
MockQuicSession session_;
MockQuicTransportSessionInterface interface_;
QuicTransportStream* stream_; // Owned by |session_|.
MockStreamVisitor* visitor_; // Owned by |stream_|.
};
TEST_F(QuicTransportStreamTest, NotReady) {
EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(false));
ReceiveStreamData("test", 0);
EXPECT_EQ(stream_->ReadableBytes(), 0u);
EXPECT_FALSE(stream_->CanWrite());
}
TEST_F(QuicTransportStreamTest, ReadWhenNotReady) {
EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(false));
ReceiveStreamData("test", 0);
char buffer[4];
WebTransportStream::ReadResult result = stream_->Read(buffer, sizeof(buffer));
EXPECT_EQ(result.bytes_read, 0u);
EXPECT_FALSE(result.fin);
}
TEST_F(QuicTransportStreamTest, WriteWhenNotReady) {
EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(false));
EXPECT_FALSE(stream_->Write("test"));
}
TEST_F(QuicTransportStreamTest, Ready) {
EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(true));
ReceiveStreamData("test", 0);
EXPECT_EQ(stream_->ReadableBytes(), 4u);
EXPECT_TRUE(stream_->CanWrite());
EXPECT_TRUE(stream_->Write("test"));
}
TEST_F(QuicTransportStreamTest, ReceiveData) {
EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(true));
EXPECT_CALL(*visitor_, OnCanRead());
ReceiveStreamData("test", 0);
std::string buffer;
WebTransportStream::ReadResult result = stream_->Read(&buffer);
EXPECT_EQ(result.bytes_read, 4u);
EXPECT_FALSE(result.fin);
EXPECT_EQ(buffer, "test");
}
TEST_F(QuicTransportStreamTest, FinReadWithNoDataPending) {
EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(true));
EXPECT_CALL(*visitor_, OnCanRead());
QuicStreamFrame frame(0, true, 0, "");
stream_->OnStreamFrame(frame);
std::string buffer;
WebTransportStream::ReadResult result = stream_->Read(&buffer);
EXPECT_EQ(result.bytes_read, 0u);
EXPECT_TRUE(result.fin);
EXPECT_EQ(buffer, "");
}
TEST_F(QuicTransportStreamTest, FinReadWithDataPending) {
EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(true));
EXPECT_CALL(*visitor_, OnCanRead());
QuicStreamFrame frame(0, true, 0, "test");
stream_->OnStreamFrame(frame);
char buffer[2];
WebTransportStream::ReadResult result = stream_->Read(buffer, sizeof(buffer));
EXPECT_EQ(result.bytes_read, 2u);
EXPECT_FALSE(result.fin);
EXPECT_EQ(buffer[0], 't');
EXPECT_EQ(buffer[1], 'e');
result = stream_->Read(buffer, sizeof(buffer));
EXPECT_EQ(result.bytes_read, 2u);
EXPECT_TRUE(result.fin);
EXPECT_EQ(buffer[0], 's');
EXPECT_EQ(buffer[1], 't');
}
TEST_F(QuicTransportStreamTest, WritingTooMuchData) {
EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(true));
ASSERT_TRUE(stream_->CanWrite());
std::string a_little_bit_of_data(128, 'A');
std::string a_lot_of_data(GetQuicFlag(FLAGS_quic_buffered_data_threshold) * 2,
'a');
EXPECT_TRUE(stream_->Write(a_little_bit_of_data));
EXPECT_TRUE(stream_->Write(a_little_bit_of_data));
EXPECT_TRUE(stream_->Write(a_little_bit_of_data));
EXPECT_TRUE(stream_->Write(a_lot_of_data));
EXPECT_FALSE(stream_->Write(a_lot_of_data));
}
TEST_F(QuicTransportStreamTest, CannotSendFinTwice) {
EXPECT_CALL(interface_, IsSessionReady()).WillRepeatedly(Return(true));
ASSERT_TRUE(stream_->CanWrite());
EXPECT_CALL(session_, WritevData(stream_->id(), _, _, _, _, _))
.WillOnce(Return(QuicConsumedData(0, /*fin_consumed=*/true)));
EXPECT_TRUE(stream_->SendFin());
EXPECT_FALSE(stream_->CanWrite());
}
} // namespace
} // namespace test
} // namespace quic