1 // Copyright (c) 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/quic/qbone/qbone_packet_exchanger.h"
6
7 #include <utility>
8
9 #include "quiche/quic/platform/api/quic_test.h"
10 #include "quiche/quic/qbone/mock_qbone_client.h"
11
12 namespace quic {
13 namespace {
14
15 using ::testing::StrEq;
16 using ::testing::StrictMock;
17
18 const size_t kMaxPendingPackets = 2;
19
20 class MockVisitor : public QbonePacketExchanger::Visitor {
21 public:
22 MOCK_METHOD(void, OnReadError, (const std::string&), (override));
23 MOCK_METHOD(void, OnWriteError, (const std::string&), (override));
24 };
25
26 class FakeQbonePacketExchanger : public QbonePacketExchanger {
27 public:
28 using QbonePacketExchanger::QbonePacketExchanger;
29
30 // Adds a packet to the end of list of packets to be returned by ReadPacket.
31 // When the list is empty, ReadPacket returns nullptr to signify error as
32 // defined by QbonePacketExchanger. If SetReadError is not called or called
33 // with empty error string, ReadPacket sets blocked to true.
AddPacketToBeRead(std::unique_ptr<QuicData> packet)34 void AddPacketToBeRead(std::unique_ptr<QuicData> packet) {
35 packets_to_be_read_.push_back(std::move(packet));
36 }
37
38 // Sets the error to be returned by ReadPacket when the list of packets is
39 // empty. If error is empty string, blocked is set by ReadPacket.
SetReadError(const std::string & error)40 void SetReadError(const std::string& error) { read_error_ = error; }
41
42 // Force WritePacket to fail with the given status. WritePacket returns true
43 // when blocked == true and error is empty.
ForceWriteFailure(bool blocked,const std::string & error)44 void ForceWriteFailure(bool blocked, const std::string& error) {
45 write_blocked_ = blocked;
46 write_error_ = error;
47 }
48
49 // Packets that have been successfully written by WritePacket.
packets_written() const50 const std::vector<std::string>& packets_written() const {
51 return packets_written_;
52 }
53
54 private:
55 // Implements QbonePacketExchanger::ReadPacket.
ReadPacket(bool * blocked,std::string * error)56 std::unique_ptr<QuicData> ReadPacket(bool* blocked,
57 std::string* error) override {
58 *blocked = false;
59
60 if (packets_to_be_read_.empty()) {
61 *blocked = read_error_.empty();
62 *error = read_error_;
63 return nullptr;
64 }
65
66 std::unique_ptr<QuicData> packet = std::move(packets_to_be_read_.front());
67 packets_to_be_read_.pop_front();
68 return packet;
69 }
70
71 // Implements QbonePacketExchanger::WritePacket.
WritePacket(const char * packet,size_t size,bool * blocked,std::string * error)72 bool WritePacket(const char* packet, size_t size, bool* blocked,
73 std::string* error) override {
74 *blocked = false;
75
76 if (write_blocked_ || !write_error_.empty()) {
77 *blocked = write_blocked_;
78 *error = write_error_;
79 return false;
80 }
81
82 packets_written_.push_back(std::string(packet, size));
83 return true;
84 }
85
86 std::string read_error_;
87 std::list<std::unique_ptr<QuicData>> packets_to_be_read_;
88
89 std::string write_error_;
90 bool write_blocked_ = false;
91 std::vector<std::string> packets_written_;
92 };
93
TEST(QbonePacketExchangerTest,ReadAndDeliverPacketDeliversPacketToQboneClient)94 TEST(QbonePacketExchangerTest,
95 ReadAndDeliverPacketDeliversPacketToQboneClient) {
96 StrictMock<MockVisitor> visitor;
97 FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
98 StrictMock<MockQboneClient> client;
99
100 std::string packet = "data";
101 exchanger.AddPacketToBeRead(
102 std::make_unique<QuicData>(packet.data(), packet.length()));
103 EXPECT_CALL(client, ProcessPacketFromNetwork(StrEq("data")));
104
105 EXPECT_TRUE(exchanger.ReadAndDeliverPacket(&client));
106 }
107
TEST(QbonePacketExchangerTest,ReadAndDeliverPacketNotifiesVisitorOnReadFailure)108 TEST(QbonePacketExchangerTest,
109 ReadAndDeliverPacketNotifiesVisitorOnReadFailure) {
110 MockVisitor visitor;
111 FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
112 MockQboneClient client;
113
114 // Force read error.
115 std::string io_error = "I/O error";
116 exchanger.SetReadError(io_error);
117 EXPECT_CALL(visitor, OnReadError(StrEq(io_error))).Times(1);
118
119 EXPECT_FALSE(exchanger.ReadAndDeliverPacket(&client));
120 }
121
TEST(QbonePacketExchangerTest,ReadAndDeliverPacketDoesNotNotifyVisitorOnBlockedIO)122 TEST(QbonePacketExchangerTest,
123 ReadAndDeliverPacketDoesNotNotifyVisitorOnBlockedIO) {
124 MockVisitor visitor;
125 FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
126 MockQboneClient client;
127
128 // No more packets to read.
129 EXPECT_FALSE(exchanger.ReadAndDeliverPacket(&client));
130 }
131
TEST(QbonePacketExchangerTest,WritePacketToNetworkWritesDirectlyToNetworkWhenNotBlocked)132 TEST(QbonePacketExchangerTest,
133 WritePacketToNetworkWritesDirectlyToNetworkWhenNotBlocked) {
134 MockVisitor visitor;
135 FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
136 MockQboneClient client;
137
138 std::string packet = "data";
139 exchanger.WritePacketToNetwork(packet.data(), packet.length());
140
141 ASSERT_EQ(exchanger.packets_written().size(), 1);
142 EXPECT_THAT(exchanger.packets_written()[0], StrEq(packet));
143 }
144
TEST(QbonePacketExchangerTest,WritePacketToNetworkQueuesPacketsAndProcessThemLater)145 TEST(QbonePacketExchangerTest,
146 WritePacketToNetworkQueuesPacketsAndProcessThemLater) {
147 MockVisitor visitor;
148 FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
149 MockQboneClient client;
150
151 // Force write to be blocked so that packets are queued.
152 exchanger.ForceWriteFailure(true, "");
153 std::vector<std::string> packets = {"packet0", "packet1"};
154 for (int i = 0; i < packets.size(); i++) {
155 exchanger.WritePacketToNetwork(packets[i].data(), packets[i].length());
156 }
157
158 // Nothing should have been written because of blockage.
159 ASSERT_TRUE(exchanger.packets_written().empty());
160
161 // Remove blockage and start proccessing queued packets.
162 exchanger.ForceWriteFailure(false, "");
163 exchanger.SetWritable();
164
165 // Queued packets are processed.
166 ASSERT_EQ(exchanger.packets_written().size(), 2);
167 for (int i = 0; i < packets.size(); i++) {
168 EXPECT_THAT(exchanger.packets_written()[i], StrEq(packets[i]));
169 }
170 }
171
TEST(QbonePacketExchangerTest,SetWritableContinuesProcessingPacketIfPreviousCallBlocked)172 TEST(QbonePacketExchangerTest,
173 SetWritableContinuesProcessingPacketIfPreviousCallBlocked) {
174 MockVisitor visitor;
175 FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
176 MockQboneClient client;
177
178 // Force write to be blocked so that packets are queued.
179 exchanger.ForceWriteFailure(true, "");
180 std::vector<std::string> packets = {"packet0", "packet1"};
181 for (int i = 0; i < packets.size(); i++) {
182 exchanger.WritePacketToNetwork(packets[i].data(), packets[i].length());
183 }
184
185 // Nothing should have been written because of blockage.
186 ASSERT_TRUE(exchanger.packets_written().empty());
187
188 // Start processing packets, but since writes are still blocked, nothing
189 // should have been written.
190 exchanger.SetWritable();
191 ASSERT_TRUE(exchanger.packets_written().empty());
192
193 // Remove blockage and start processing packets again.
194 exchanger.ForceWriteFailure(false, "");
195 exchanger.SetWritable();
196
197 ASSERT_EQ(exchanger.packets_written().size(), 2);
198 for (int i = 0; i < packets.size(); i++) {
199 EXPECT_THAT(exchanger.packets_written()[i], StrEq(packets[i]));
200 }
201 }
202
TEST(QbonePacketExchangerTest,WritePacketToNetworkDropsPacketIfQueueIfFull)203 TEST(QbonePacketExchangerTest, WritePacketToNetworkDropsPacketIfQueueIfFull) {
204 std::vector<std::string> packets = {"packet0", "packet1", "packet2"};
205 size_t queue_size = packets.size() - 1;
206 MockVisitor visitor;
207 // exchanger has smaller queue than number of packets.
208 FakeQbonePacketExchanger exchanger(&visitor, queue_size);
209 MockQboneClient client;
210
211 exchanger.ForceWriteFailure(true, "");
212 for (int i = 0; i < packets.size(); i++) {
213 exchanger.WritePacketToNetwork(packets[i].data(), packets[i].length());
214 }
215
216 // Blocked writes cause packets to be queued or dropped.
217 ASSERT_TRUE(exchanger.packets_written().empty());
218
219 exchanger.ForceWriteFailure(false, "");
220 exchanger.SetWritable();
221
222 ASSERT_EQ(exchanger.packets_written().size(), queue_size);
223 for (int i = 0; i < queue_size; i++) {
224 EXPECT_THAT(exchanger.packets_written()[i], StrEq(packets[i]));
225 }
226 }
227
TEST(QbonePacketExchangerTest,WriteErrorsGetNotified)228 TEST(QbonePacketExchangerTest, WriteErrorsGetNotified) {
229 MockVisitor visitor;
230 FakeQbonePacketExchanger exchanger(&visitor, kMaxPendingPackets);
231 MockQboneClient client;
232 std::string packet = "data";
233
234 // Write error is delivered to visitor during WritePacketToNetwork.
235 std::string io_error = "I/O error";
236 exchanger.ForceWriteFailure(false, io_error);
237 EXPECT_CALL(visitor, OnWriteError(StrEq(io_error))).Times(1);
238 exchanger.WritePacketToNetwork(packet.data(), packet.length());
239 ASSERT_TRUE(exchanger.packets_written().empty());
240
241 // Write error is delivered to visitor during SetWritable.
242 exchanger.ForceWriteFailure(true, "");
243 exchanger.WritePacketToNetwork(packet.data(), packet.length());
244
245 std::string sys_error = "sys error";
246 exchanger.ForceWriteFailure(false, sys_error);
247 EXPECT_CALL(visitor, OnWriteError(StrEq(sys_error))).Times(1);
248 exchanger.SetWritable();
249 ASSERT_TRUE(exchanger.packets_written().empty());
250 }
251
TEST(QbonePacketExchangerTest,NullVisitorDoesntCrash)252 TEST(QbonePacketExchangerTest, NullVisitorDoesntCrash) {
253 FakeQbonePacketExchanger exchanger(nullptr, kMaxPendingPackets);
254 MockQboneClient client;
255 std::string packet = "data";
256
257 // Force read error.
258 std::string io_error = "I/O error";
259 exchanger.SetReadError(io_error);
260 EXPECT_FALSE(exchanger.ReadAndDeliverPacket(&client));
261
262 // Force write error
263 exchanger.ForceWriteFailure(false, io_error);
264 exchanger.WritePacketToNetwork(packet.data(), packet.length());
265 EXPECT_TRUE(exchanger.packets_written().empty());
266 }
267
268 } // namespace
269 } // namespace quic
270