0
Files
src/net/quic/quic_socket_data_provider_unittest.cc
Xinan Lin 8df3d6dd92 Print Setting frame for QuicSocketDataProvider if VerifyWriteData fails
The Setting frame is handled by the server's pending streams in
production, which requires encryption established.
But in unit tests, this is not necessary, because the goal for this QUIC
server session is to decode various HTTP frames.
So create a subclass from QuicSimpleServerSessionforTest
and override IsEncryptionEstablished to be always true.

BUG=366568084
TEST=net_unittests \
  --gtest_filter=QuicSocketDataProviderTest.PrintInitialSettingsPacket

Change-Id: Icc60eb0e20ea8ec63c0b4ff003c16342fc5ce1e0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6055526
Reviewed-by: Adam Langley <agl@chromium.org>
Commit-Queue: Xinan Lin <linxinan@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1396283}
2024-12-13 17:01:26 -08:00

552 lines
22 KiB
C++

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/quic/quic_socket_data_provider.h"
#include <memory>
#include "base/strings/string_number_conversions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/bind.h"
#include "base/test/gtest_util.h"
#include "net/base/io_buffer.h"
#include "net/base/request_priority.h"
#include "net/quic/mock_quic_context.h"
#include "net/quic/quic_http_utils.h"
#include "net/quic/quic_test_packet_maker.h"
#include "net/socket/datagram_client_socket.h"
#include "net/socket/diff_serv_code_point.h"
#include "net/socket/socket_test_util.h"
#include "net/test/test_with_task_environment.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "testing/gtest/include/gtest/gtest-spi.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net::test {
class QuicSocketDataProviderTest : public TestWithTaskEnvironment {
public:
QuicSocketDataProviderTest()
: packet_maker_(std::make_unique<QuicTestPacketMaker>(
version_,
quic::QuicUtils::CreateRandomConnectionId(
context_.random_generator()),
context_.clock(),
"hostname",
quic::Perspective::IS_CLIENT,
/*client_priority_uses_incremental=*/true,
/*use_priority_header=*/true)) {}
// Create a simple test packet.
std::unique_ptr<quic::QuicReceivedPacket> TestPacket(uint64_t packet_number) {
return packet_maker_->Packet(packet_number)
.AddMessageFrame(base::NumberToString(packet_number))
.Build();
}
std::unique_ptr<quic::QuicReceivedPacket> TestInitialSettingsPacket(
uint64_t packet_number) {
return packet_maker_->MakeInitialSettingsPacket(packet_number);
}
// Create a simple request header packet.
std::unique_ptr<quic::QuicReceivedPacket>
TestHeadersPacket(uint64_t packet_number, std::string path, bool fin) {
quiche::HttpHeaderBlock headers;
headers[":scheme"] = "https";
headers[":path"] = path;
spdy::SpdyPriority priority =
ConvertRequestPriorityToQuicPriority(DEFAULT_PRIORITY);
size_t spdy_headers_frame_len;
// Headers frame should be sent with stream 0.
auto rv = packet_maker_->MakeRequestHeadersPacket(
packet_number, 0, fin, priority, std::move(headers),
&spdy_headers_frame_len, /*should_include_priority_frame=*/false);
return rv;
}
protected:
NetLogWithSource net_log_with_source_{
NetLogWithSource::Make(NetLogSourceType::NONE)};
quic::ParsedQuicVersion version_ = quic::ParsedQuicVersion::RFCv1();
MockQuicContext context_;
std::unique_ptr<QuicTestPacketMaker> packet_maker_;
};
// A linear sequence of sync expectations completes.
TEST_F(QuicSocketDataProviderTest, LinearSequenceSync) {
QuicSocketDataProvider socket_data(version_);
MockClientSocketFactory socket_factory;
socket_data.AddWrite("p1", TestPacket(1)).Sync();
socket_data.AddWrite("p2", TestPacket(2)).Sync();
socket_data.AddWrite("p3", TestPacket(3)).Sync();
socket_factory.AddSocketDataProvider(&socket_data);
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindLambdaForTesting([&]() {
std::unique_ptr<DatagramClientSocket> socket =
socket_factory.CreateDatagramClientSocket(
DatagramSocket::BindType::DEFAULT_BIND, nullptr,
net_log_with_source_.source());
socket->Connect(IPEndPoint());
for (uint64_t packet_number = 1; packet_number < 4; packet_number++) {
std::unique_ptr<quic::QuicReceivedPacket> packet =
TestPacket(packet_number);
scoped_refptr<StringIOBuffer> buffer =
base::MakeRefCounted<StringIOBuffer>(
std::string(packet->data(), packet->length()));
EXPECT_EQ(
static_cast<int>(packet->length()),
socket->Write(buffer.get(), packet->length(), base::DoNothing(),
TRAFFIC_ANNOTATION_FOR_TESTS));
}
}));
socket_data.RunUntilAllConsumed();
}
// A linear sequence of async expectations completes.
TEST_F(QuicSocketDataProviderTest, LinearSequenceAsync) {
QuicSocketDataProvider socket_data(version_);
MockClientSocketFactory socket_factory;
socket_data.AddWrite("p1", TestPacket(1));
socket_data.AddWrite("p2", TestPacket(2));
socket_data.AddWrite("p3", TestPacket(3));
socket_factory.AddSocketDataProvider(&socket_data);
std::unique_ptr<DatagramClientSocket> socket =
socket_factory.CreateDatagramClientSocket(
DatagramSocket::BindType::DEFAULT_BIND, nullptr,
net_log_with_source_.source());
socket->Connect(IPEndPoint());
int next_packet = 1;
base::RepeatingCallback<void(int)> callback =
base::BindLambdaForTesting([&](int result) {
EXPECT_GT(result, 0); // Bytes written or, on the first call, one.
if (next_packet <= 3) {
std::unique_ptr<quic::QuicReceivedPacket> packet =
TestPacket(next_packet++);
scoped_refptr<StringIOBuffer> buffer =
base::MakeRefCounted<StringIOBuffer>(
std::string(packet->data(), packet->length()));
EXPECT_EQ(ERR_IO_PENDING,
socket->Write(buffer.get(), packet->length(), callback,
TRAFFIC_ANNOTATION_FOR_TESTS));
}
});
callback.Run(1);
socket_data.RunUntilAllConsumed();
}
// The `TosByte` builder method results in a correct TOS byte in the read.
TEST_F(QuicSocketDataProviderTest, ReadTos) {
QuicSocketDataProvider socket_data(version_);
MockClientSocketFactory socket_factory;
const uint8_t kTestTos = (DSCP_CS1 << 2) + ECN_CE;
socket_data.AddRead("p1", TestPacket(1)).Sync().TosByte(kTestTos);
socket_factory.AddSocketDataProvider(&socket_data);
std::unique_ptr<DatagramClientSocket> socket =
socket_factory.CreateDatagramClientSocket(
DatagramSocket::BindType::DEFAULT_BIND, nullptr,
net_log_with_source_.source());
socket->Connect(IPEndPoint());
scoped_refptr<GrowableIOBuffer> read_buffer =
base::MakeRefCounted<GrowableIOBuffer>();
read_buffer->SetCapacity(100);
EXPECT_EQ(static_cast<int>(TestPacket(1)->length()),
socket->Read(read_buffer.get(), 100, base::DoNothing()));
DscpAndEcn dscp_and_ecn = socket->GetLastTos();
EXPECT_EQ(dscp_and_ecn.dscp, DSCP_CS1);
EXPECT_EQ(dscp_and_ecn.ecn, ECN_CE);
socket_data.RunUntilAllConsumed();
}
// AddReadError creates a read returning an error.
TEST_F(QuicSocketDataProviderTest, AddReadError) {
QuicSocketDataProvider socket_data(version_);
MockClientSocketFactory socket_factory;
socket_data.AddReadError("p1", ERR_CONNECTION_ABORTED).Sync();
socket_factory.AddSocketDataProvider(&socket_data);
std::unique_ptr<DatagramClientSocket> socket =
socket_factory.CreateDatagramClientSocket(
DatagramSocket::BindType::DEFAULT_BIND, nullptr,
net_log_with_source_.source());
socket->Connect(IPEndPoint());
scoped_refptr<GrowableIOBuffer> read_buffer =
base::MakeRefCounted<GrowableIOBuffer>();
read_buffer->SetCapacity(100);
EXPECT_EQ(ERR_CONNECTION_ABORTED,
socket->Read(read_buffer.get(), 100, base::DoNothing()));
socket_data.RunUntilAllConsumed();
}
// AddRead with a QuicReceivedPacket correctly sets the ECN.
TEST_F(QuicSocketDataProviderTest, AddReadQuicReceivedPacketGetsEcn) {
QuicSocketDataProvider socket_data(version_);
MockClientSocketFactory socket_factory;
packet_maker_->set_ecn_codepoint(quic::QuicEcnCodepoint::ECN_ECT0);
socket_data.AddRead("p1", TestPacket(1)).Sync();
socket_factory.AddSocketDataProvider(&socket_data);
std::unique_ptr<DatagramClientSocket> socket =
socket_factory.CreateDatagramClientSocket(
DatagramSocket::BindType::DEFAULT_BIND, nullptr,
net_log_with_source_.source());
socket->Connect(IPEndPoint());
scoped_refptr<GrowableIOBuffer> read_buffer =
base::MakeRefCounted<GrowableIOBuffer>();
read_buffer->SetCapacity(100);
EXPECT_EQ(static_cast<int>(TestPacket(1)->length()),
socket->Read(read_buffer.get(), 100, base::DoNothing()));
DscpAndEcn dscp_and_ecn = socket->GetLastTos();
EXPECT_EQ(dscp_and_ecn.ecn, ECN_ECT0);
socket_data.RunUntilAllConsumed();
EXPECT_TRUE(socket_data.AllReadDataConsumed());
EXPECT_TRUE(socket_data.AllWriteDataConsumed());
}
// A write of data different from the expectation generates a failure.
TEST_F(QuicSocketDataProviderTest, MismatchedWrite) {
QuicSocketDataProvider socket_data(version_);
MockClientSocketFactory socket_factory;
socket_data.AddWrite("p1", TestPacket(1)).Sync();
socket_factory.AddSocketDataProvider(&socket_data);
std::unique_ptr<DatagramClientSocket> socket =
socket_factory.CreateDatagramClientSocket(
DatagramSocket::BindType::DEFAULT_BIND, nullptr,
net_log_with_source_.source());
socket->Connect(IPEndPoint());
std::unique_ptr<quic::QuicReceivedPacket> packet = TestPacket(999);
scoped_refptr<StringIOBuffer> buffer = base::MakeRefCounted<StringIOBuffer>(
std::string(packet->data(), packet->length()));
EXPECT_NONFATAL_FAILURE(
EXPECT_EQ(ERR_UNEXPECTED,
socket->Write(buffer.get(), packet->length(), base::DoNothing(),
TRAFFIC_ANNOTATION_FOR_TESTS)),
"Expectation 'p1' not met.");
}
// AllDataConsumed is false if there are still pending expectations.
TEST_F(QuicSocketDataProviderTest, NotAllConsumed) {
QuicSocketDataProvider socket_data(version_);
MockClientSocketFactory socket_factory;
socket_data.AddWrite("p1", TestPacket(1)).Sync();
socket_data.AddWrite("p2", TestPacket(2)).Sync();
socket_factory.AddSocketDataProvider(&socket_data);
std::unique_ptr<DatagramClientSocket> socket =
socket_factory.CreateDatagramClientSocket(
DatagramSocket::BindType::DEFAULT_BIND, nullptr,
net_log_with_source_.source());
socket->Connect(IPEndPoint());
std::unique_ptr<quic::QuicReceivedPacket> packet = TestPacket(1);
scoped_refptr<StringIOBuffer> buffer = base::MakeRefCounted<StringIOBuffer>(
std::string(packet->data(), packet->length()));
EXPECT_EQ(static_cast<int>(packet->length()),
socket->Write(buffer.get(), packet->length(), base::DoNothing(),
TRAFFIC_ANNOTATION_FOR_TESTS));
EXPECT_FALSE(socket_data.AllDataConsumed());
}
// When a Write call occurs with no matching expectation, that is treated as an
// error.
TEST_F(QuicSocketDataProviderTest, ReadBlocksWrite) {
QuicSocketDataProvider socket_data(version_);
MockClientSocketFactory socket_factory;
socket_data.AddRead("p1", TestPacket(1)).Sync();
socket_data.AddWrite("p2", TestPacket(2)).Sync();
socket_factory.AddSocketDataProvider(&socket_data);
std::unique_ptr<DatagramClientSocket> socket =
socket_factory.CreateDatagramClientSocket(
DatagramSocket::BindType::DEFAULT_BIND, nullptr,
net_log_with_source_.source());
socket->Connect(IPEndPoint());
std::unique_ptr<quic::QuicReceivedPacket> packet = TestPacket(1);
scoped_refptr<StringIOBuffer> buffer = base::MakeRefCounted<StringIOBuffer>(
std::string(packet->data(), packet->length()));
EXPECT_NONFATAL_FAILURE(
EXPECT_EQ(ERR_UNEXPECTED,
socket->Write(buffer.get(), packet->length(), base::DoNothing(),
TRAFFIC_ANNOTATION_FOR_TESTS)),
"Write call when none is expected:");
}
// When a Read call occurs with no matching expectation, it waits for a matching
// expectation to become read.
TEST_F(QuicSocketDataProviderTest, WriteDelaysRead) {
QuicSocketDataProvider socket_data(version_);
MockClientSocketFactory socket_factory;
socket_data.AddWrite("p1", TestPacket(1)).Sync();
socket_data.AddRead("p2", TestPacket(22222)).Sync();
socket_factory.AddSocketDataProvider(&socket_data);
std::unique_ptr<DatagramClientSocket> socket =
socket_factory.CreateDatagramClientSocket(
DatagramSocket::BindType::DEFAULT_BIND, nullptr,
net_log_with_source_.source());
socket->Connect(IPEndPoint());
// Begin a read operation which should not complete yet.
bool read_completed = false;
base::OnceCallback<void(int)> read_callback =
base::BindLambdaForTesting([&](int result) {
EXPECT_EQ(result, static_cast<int>(TestPacket(22222)->length()));
read_completed = true;
});
scoped_refptr<GrowableIOBuffer> read_buffer =
base::MakeRefCounted<GrowableIOBuffer>();
read_buffer->SetCapacity(100);
EXPECT_EQ(ERR_IO_PENDING,
socket->Read(read_buffer.get(), 100, std::move(read_callback)));
EXPECT_FALSE(read_completed);
// Perform the write on which the read depends.
std::unique_ptr<quic::QuicReceivedPacket> packet = TestPacket(1);
scoped_refptr<StringIOBuffer> buffer = base::MakeRefCounted<StringIOBuffer>(
std::string(packet->data(), packet->length()));
EXPECT_EQ(static_cast<int>(packet->length()),
socket->Write(buffer.get(), packet->length(), base::DoNothing(),
TRAFFIC_ANNOTATION_FOR_TESTS));
socket_data.RunUntilAllConsumed();
EXPECT_TRUE(read_completed);
}
// When a pause becomes ready, subsequent calls are delayed.
TEST_F(QuicSocketDataProviderTest, PauseDelaysCalls) {
QuicSocketDataProvider socket_data(version_);
MockClientSocketFactory socket_factory;
socket_data.AddWrite("p1", TestPacket(1)).Sync();
auto pause = socket_data.AddPause("pause");
socket_data.AddRead("p2", TestPacket(2)).After("pause");
socket_data.AddWrite("p3", TestPacket(3)).After("pause");
socket_factory.AddSocketDataProvider(&socket_data);
std::unique_ptr<DatagramClientSocket> socket =
socket_factory.CreateDatagramClientSocket(
DatagramSocket::BindType::DEFAULT_BIND, nullptr,
net_log_with_source_.source());
socket->Connect(IPEndPoint());
// Perform a write in another task, and wait for the pause.
bool write_completed = false;
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindLambdaForTesting([&]() {
std::unique_ptr<quic::QuicReceivedPacket> packet = TestPacket(1);
scoped_refptr<StringIOBuffer> buffer =
base::MakeRefCounted<StringIOBuffer>(
std::string(packet->data(), packet->length()));
EXPECT_EQ(
static_cast<int>(packet->length()),
socket->Write(buffer.get(), packet->length(), base::DoNothing(),
TRAFFIC_ANNOTATION_FOR_TESTS));
write_completed = true;
}));
EXPECT_FALSE(write_completed);
socket_data.RunUntilPause(pause);
EXPECT_TRUE(write_completed);
// Begin a read operation which should not complete yet.
bool read_completed = false;
base::OnceCallback<void(int)> read_callback =
base::BindLambdaForTesting([&](int result) {
EXPECT_EQ(result, static_cast<int>(TestPacket(2)->length()));
read_completed = true;
});
scoped_refptr<GrowableIOBuffer> read_buffer =
base::MakeRefCounted<GrowableIOBuffer>();
read_buffer->SetCapacity(100);
EXPECT_EQ(ERR_IO_PENDING,
socket->Read(read_buffer.get(), 100, std::move(read_callback)));
// Begin a write operation which should not complete yet.
write_completed = false;
base::OnceCallback<void(int)> write_callback =
base::BindLambdaForTesting([&](int result) {
EXPECT_EQ(result, static_cast<int>(TestPacket(3)->length()));
write_completed = true;
});
std::unique_ptr<quic::QuicReceivedPacket> packet = TestPacket(3);
scoped_refptr<StringIOBuffer> buffer = base::MakeRefCounted<StringIOBuffer>(
std::string(packet->data(), packet->length()));
EXPECT_EQ(ERR_IO_PENDING, socket->Write(buffer.get(), packet->length(),
std::move(write_callback),
TRAFFIC_ANNOTATION_FOR_TESTS));
EXPECT_FALSE(read_completed);
EXPECT_FALSE(write_completed);
socket_data.Resume();
socket_data.RunUntilAllConsumed();
RunUntilIdle();
EXPECT_TRUE(read_completed);
EXPECT_TRUE(write_completed);
}
// Using `After`, a `Read` and `Write` can be allowed in either order.
TEST_F(QuicSocketDataProviderTest, ParallelReadAndWrite) {
for (bool read_first : {false, true}) {
SCOPED_TRACE(::testing::Message() << "read_first: " << read_first);
QuicSocketDataProvider socket_data(version_);
MockClientSocketFactory socket_factory;
socket_data.AddWrite("p1", TestPacket(1)).Sync();
socket_data.AddRead("p2", TestPacket(2)).Sync().After("p1");
socket_data.AddWrite("p3", TestPacket(3)).Sync().After("p1");
socket_factory.AddSocketDataProvider(&socket_data);
std::unique_ptr<DatagramClientSocket> socket =
socket_factory.CreateDatagramClientSocket(
DatagramSocket::BindType::DEFAULT_BIND, nullptr,
net_log_with_source_.source());
socket->Connect(IPEndPoint());
// Write p1 to get things started.
std::unique_ptr<quic::QuicReceivedPacket> packet = TestPacket(1);
scoped_refptr<IOBuffer> buffer = base::MakeRefCounted<StringIOBuffer>(
std::string(packet->data(), packet->length()));
EXPECT_EQ(static_cast<int>(packet->length()),
socket->Write(buffer.get(), packet->length(), base::DoNothing(),
TRAFFIC_ANNOTATION_FOR_TESTS));
scoped_refptr<GrowableIOBuffer> read_buffer =
base::MakeRefCounted<GrowableIOBuffer>();
read_buffer->SetCapacity(100);
auto do_read = [&]() {
EXPECT_EQ(static_cast<int>(TestPacket(2)->length()),
socket->Read(read_buffer.get(), 100, base::DoNothing()));
};
std::unique_ptr<quic::QuicReceivedPacket> write_packet = TestPacket(3);
buffer = base::MakeRefCounted<StringIOBuffer>(
std::string(write_packet->data(), write_packet->length()));
auto do_write = [&]() {
EXPECT_EQ(static_cast<int>(write_packet->length()),
socket->Write(buffer.get(), write_packet->length(),
base::DoNothing(), TRAFFIC_ANNOTATION_FOR_TESTS));
};
// Read p2 and write p3 in both orders.
if (read_first) {
do_read();
do_write();
} else {
do_write();
do_read();
}
socket_data.RunUntilAllConsumed();
}
}
// When multiple Read expectations become ready at the same time, fail with a
// CHECK error.
TEST_F(QuicSocketDataProviderTest, MultipleReadsReady) {
QuicSocketDataProvider socket_data(version_);
MockClientSocketFactory socket_factory;
socket_data.AddWrite("p1", TestPacket(1)).Sync();
socket_data.AddRead("p2", TestPacket(2)).After("p1");
socket_data.AddRead("p3", TestPacket(3)).After("p1");
socket_factory.AddSocketDataProvider(&socket_data);
std::unique_ptr<DatagramClientSocket> socket =
socket_factory.CreateDatagramClientSocket(
DatagramSocket::BindType::DEFAULT_BIND, nullptr,
net_log_with_source_.source());
socket->Connect(IPEndPoint());
std::unique_ptr<quic::QuicReceivedPacket> packet = TestPacket(1);
scoped_refptr<StringIOBuffer> buffer = base::MakeRefCounted<StringIOBuffer>(
std::string(packet->data(), packet->length()));
EXPECT_EQ(static_cast<int>(packet->length()),
socket->Write(buffer.get(), packet->length(), base::DoNothing(),
TRAFFIC_ANNOTATION_FOR_TESTS));
EXPECT_CHECK_DEATH(
socket->Read(buffer.get(), buffer->size(), base::DoNothing()));
}
// Test an HTTP header packet is decoded by the server session.
TEST_F(QuicSocketDataProviderTest, PrintHTTPHeadersPacket) {
QuicSocketDataProvider socket_data(version_);
MockClientSocketFactory socket_factory;
const std::string path = "/.well-known/masque/udp/www.example.org/443/";
socket_data.AddWrite("connect-udp", TestHeadersPacket(2, path, false));
socket_factory.AddSocketDataProvider(&socket_data);
std::unique_ptr<DatagramClientSocket> socket =
socket_factory.CreateDatagramClientSocket(
DatagramSocket::BindType::DEFAULT_BIND, nullptr,
net_log_with_source_.source());
socket->Connect(IPEndPoint());
std::unique_ptr<quic::QuicReceivedPacket> packet = TestPacket(999);
scoped_refptr<StringIOBuffer> buffer = base::MakeRefCounted<StringIOBuffer>(
std::string(packet->data(), packet->length()));
EXPECT_NONFATAL_FAILURE(
EXPECT_EQ(ERR_UNEXPECTED,
socket->Write(buffer.get(), packet->length(), base::DoNothing(),
TRAFFIC_ANNOTATION_FOR_TESTS)),
// Path should be decoded by the server session and appear in the output.
std::format(":path={0}", path));
}
// Test an HTTP's initial settings packet is decoded by the server session.
TEST_F(QuicSocketDataProviderTest, PrintInitialSettingsPacket) {
QuicSocketDataProvider socket_data(version_);
MockClientSocketFactory socket_factory;
socket_data.AddWrite("InitialSettings", TestInitialSettingsPacket(2));
socket_factory.AddSocketDataProvider(&socket_data);
std::unique_ptr<DatagramClientSocket> socket =
socket_factory.CreateDatagramClientSocket(
DatagramSocket::BindType::DEFAULT_BIND, nullptr,
net_log_with_source_.source());
socket->Connect(IPEndPoint());
std::unique_ptr<quic::QuicReceivedPacket> packet = TestPacket(999);
scoped_refptr<StringIOBuffer> buffer = base::MakeRefCounted<StringIOBuffer>(
std::string(packet->data(), packet->length()));
EXPECT_NONFATAL_FAILURE(
EXPECT_EQ(ERR_UNEXPECTED,
socket->Write(buffer.get(), packet->length(), base::DoNothing(),
TRAFFIC_ANNOTATION_FOR_TESTS)),
// Content of the setting frame should be decoded in the output.
"SETTINGS_H3_DATAGRAM = 1;");
}
} // namespace net::test