gfe-relnote: Default-initialize QUIC BBRv2 loss event threshold for exiting STARTUP from a flag. Protected by --gfe2_reloadable_flag_quic_default_to_bbr_v2.
PiperOrigin-RevId: 264298542
Change-Id: I304ab19e4820dec51d3f8ef53762a393f6b175fd
diff --git a/quic/qbone/qbone_packet_exchanger_test.cc b/quic/qbone/qbone_packet_exchanger_test.cc
new file mode 100644
index 0000000..4e63b99
--- /dev/null
+++ b/quic/qbone/qbone_packet_exchanger_test.cc
@@ -0,0 +1,253 @@
+// 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 "net/third_party/quiche/src/quic/qbone/qbone_packet_exchanger.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/qbone/mock_qbone_client.h"
+
+namespace quic {
+namespace {
+
+using ::testing::StrEq;
+using ::testing::StrictMock;
+
+const size_t kMaxPendingPackets = 2;
+
+class MockVisitor : public QbonePacketExchanger::Visitor {
+ public:
+ MOCK_METHOD1(OnReadError, void(const string&));
+ MOCK_METHOD1(OnWriteError, void(const string&));
+};
+
+class FakeQbonePacketExchanger : public QbonePacketExchanger {
+ public:
+ using QbonePacketExchanger::QbonePacketExchanger;
+
+ // Adds a packet to the end of list of packets to be returned by ReadPacket.
+ // When the list is empty, ReadPacket returns nullptr to signify error as
+ // defined by QbonePacketExchanger. If SetReadError is not called or called
+ // with empty error string, ReadPacket sets blocked to true.
+ void AddPacketToBeRead(std::unique_ptr<QuicData> packet) {
+ packets_to_be_read_.push_back(std::move(packet));
+ }
+
+ // Sets the error to be returned by ReadPacket when the list of packets is
+ // empty. If error is empty string, blocked is set by ReadPacket.
+ void SetReadError(const string& error) { read_error_ = error; }
+
+ // Force WritePacket to fail with the given status. WritePacket returns true
+ // when blocked == true and error is empty.
+ void ForceWriteFailure(bool blocked, const string& error) {
+ write_blocked_ = blocked;
+ write_error_ = error;
+ }
+
+ // Packets that have been successfully written by WritePacket.
+ const std::vector<string>& packets_written() const {
+ return packets_written_;
+ }
+
+ private:
+ // Implements QbonePacketExchanger::ReadPacket.
+ std::unique_ptr<QuicData> ReadPacket(bool* blocked, string* error) override {
+ *blocked = false;
+
+ if (packets_to_be_read_.empty()) {
+ *blocked = read_error_.empty();
+ *error = read_error_;
+ return nullptr;
+ }
+
+ std::unique_ptr<QuicData> packet = std::move(packets_to_be_read_.front());
+ packets_to_be_read_.pop_front();
+ return packet;
+ }
+
+ // Implements QbonePacketExchanger::WritePacket.
+ bool WritePacket(const char* packet,
+ size_t size,
+ bool* blocked,
+ string* error) override {
+ *blocked = false;
+
+ if (write_blocked_ || !write_error_.empty()) {
+ *blocked = write_blocked_;
+ *error = write_error_;
+ return false;
+ }
+
+ packets_written_.push_back(string(packet, size));
+ return true;
+ }
+
+ string read_error_;
+ std::list<std::unique_ptr<QuicData>> packets_to_be_read_;
+
+ string write_error_;
+ bool write_blocked_ = false;
+ std::vector<string> packets_written_;
+};
+
+TEST(QbonePacketExchangerTest,
+ ReadAndDeliverPacketDeliversPacketToQboneClient) {
+ StrictMock<MockVisitor> visitor;
+ FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
+ StrictMock<MockQboneClient> client;
+
+ string packet = "data";
+ exchanger.AddPacketToBeRead(
+ QuicMakeUnique<QuicData>(packet.data(), packet.length()));
+ EXPECT_CALL(client, ProcessPacketFromNetwork(StrEq("data")));
+
+ EXPECT_TRUE(exchanger.ReadAndDeliverPacket(&client));
+}
+
+TEST(QbonePacketExchangerTest,
+ ReadAndDeliverPacketNotifiesVisitorOnReadFailure) {
+ MockVisitor visitor;
+ FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
+ MockQboneClient client;
+
+ // Force read error.
+ string io_error = "I/O error";
+ exchanger.SetReadError(io_error);
+ EXPECT_CALL(visitor, OnReadError(StrEq(io_error))).Times(1);
+
+ EXPECT_FALSE(exchanger.ReadAndDeliverPacket(&client));
+}
+
+TEST(QbonePacketExchangerTest,
+ ReadAndDeliverPacketDoesNotNotifyVisitorOnBlockedIO) {
+ MockVisitor visitor;
+ FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
+ MockQboneClient client;
+
+ // No more packets to read.
+ EXPECT_FALSE(exchanger.ReadAndDeliverPacket(&client));
+}
+
+TEST(QbonePacketExchangerTest,
+ WritePacketToNetworkWritesDirectlyToNetworkWhenNotBlocked) {
+ MockVisitor visitor;
+ FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
+ MockQboneClient client;
+
+ string packet = "data";
+ exchanger.WritePacketToNetwork(packet.data(), packet.length());
+
+ ASSERT_EQ(exchanger.packets_written().size(), 1);
+ EXPECT_THAT(exchanger.packets_written()[0], StrEq(packet));
+}
+
+TEST(QbonePacketExchangerTest,
+ WritePacketToNetworkQueuesPacketsAndProcessThemLater) {
+ MockVisitor visitor;
+ FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
+ MockQboneClient client;
+
+ // Force write to be blocked so that packets are queued.
+ exchanger.ForceWriteFailure(true, "");
+ std::vector<string> packets = {"packet0", "packet1"};
+ for (int i = 0; i < packets.size(); i++) {
+ exchanger.WritePacketToNetwork(packets[i].data(), packets[i].length());
+ }
+
+ // Nothing should have been written because of blockage.
+ ASSERT_TRUE(exchanger.packets_written().empty());
+
+ // Remove blockage and start proccessing queued packets.
+ exchanger.ForceWriteFailure(false, "");
+ exchanger.SetWritable();
+
+ // Queued packets are processed.
+ ASSERT_EQ(exchanger.packets_written().size(), 2);
+ for (int i = 0; i < packets.size(); i++) {
+ EXPECT_THAT(exchanger.packets_written()[i], StrEq(packets[i]));
+ }
+}
+
+TEST(QbonePacketExchangerTest,
+ SetWritableContinuesProcessingPacketIfPreviousCallBlocked) {
+ MockVisitor visitor;
+ FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
+ MockQboneClient client;
+
+ // Force write to be blocked so that packets are queued.
+ exchanger.ForceWriteFailure(true, "");
+ std::vector<string> packets = {"packet0", "packet1"};
+ for (int i = 0; i < packets.size(); i++) {
+ exchanger.WritePacketToNetwork(packets[i].data(), packets[i].length());
+ }
+
+ // Nothing should have been written because of blockage.
+ ASSERT_TRUE(exchanger.packets_written().empty());
+
+ // Start processing packets, but since writes are still blocked, nothing
+ // should have been written.
+ exchanger.SetWritable();
+ ASSERT_TRUE(exchanger.packets_written().empty());
+
+ // Remove blockage and start processing packets again.
+ exchanger.ForceWriteFailure(false, "");
+ exchanger.SetWritable();
+
+ ASSERT_EQ(exchanger.packets_written().size(), 2);
+ for (int i = 0; i < packets.size(); i++) {
+ EXPECT_THAT(exchanger.packets_written()[i], StrEq(packets[i]));
+ }
+}
+
+TEST(QbonePacketExchangerTest, WritePacketToNetworkDropsPacketIfQueueIfFull) {
+ std::vector<string> packets = {"packet0", "packet1", "packet2"};
+ size_t queue_size = packets.size() - 1;
+ MockVisitor visitor;
+ // exchanger has smaller queue than number of packets.
+ FakeQbonePacketExchanger exchanger(&visitor, queue_size);
+ MockQboneClient client;
+
+ exchanger.ForceWriteFailure(true, "");
+ for (int i = 0; i < packets.size(); i++) {
+ exchanger.WritePacketToNetwork(packets[i].data(), packets[i].length());
+ }
+
+ // Blocked writes cause packets to be queued or dropped.
+ ASSERT_TRUE(exchanger.packets_written().empty());
+
+ exchanger.ForceWriteFailure(false, "");
+ exchanger.SetWritable();
+
+ ASSERT_EQ(exchanger.packets_written().size(), queue_size);
+ for (int i = 0; i < queue_size; i++) {
+ EXPECT_THAT(exchanger.packets_written()[i], StrEq(packets[i]));
+ }
+}
+
+TEST(QbonePacketExchangerTest, WriteErrorsGetNotified) {
+ MockVisitor visitor;
+ FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
+ MockQboneClient client;
+ string packet = "data";
+
+ // Write error is delivered to visitor during WritePacketToNetwork.
+ string io_error = "I/O error";
+ exchanger.ForceWriteFailure(false, io_error);
+ EXPECT_CALL(visitor, OnWriteError(StrEq(io_error))).Times(1);
+ exchanger.WritePacketToNetwork(packet.data(), packet.length());
+ ASSERT_TRUE(exchanger.packets_written().empty());
+
+ // Write error is delivered to visitor during SetWritable.
+ exchanger.ForceWriteFailure(true, "");
+ exchanger.WritePacketToNetwork(packet.data(), packet.length());
+
+ string sys_error = "sys error";
+ exchanger.ForceWriteFailure(false, sys_error);
+ EXPECT_CALL(visitor, OnWriteError(StrEq(sys_error))).Times(1);
+ exchanger.SetWritable();
+ ASSERT_TRUE(exchanger.packets_written().empty());
+}
+
+} // namespace
+} // namespace quic