blob: 66bddcb8043a888634feced0e7238c77737e40a9 [file] [log] [blame]
vasilvv097f3722019-10-23 13:36:16 -07001// 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// An integration test that covers interactions between QuicTransport client and
6// server sessions.
7
8#include <memory>
vasilvvd88f1622019-11-04 13:50:53 -08009#include <vector>
vasilvv097f3722019-10-23 13:36:16 -070010
11#include "url/gurl.h"
12#include "url/origin.h"
13#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_client_config.h"
14#include "net/third_party/quiche/src/quic/core/crypto/quic_crypto_server_config.h"
vasilvv2b0ab242020-01-07 07:32:09 -080015#include "net/third_party/quiche/src/quic/core/quic_buffer_allocator.h"
vasilvv097f3722019-10-23 13:36:16 -070016#include "net/third_party/quiche/src/quic/core/quic_connection.h"
17#include "net/third_party/quiche/src/quic/core/quic_error_codes.h"
18#include "net/third_party/quiche/src/quic/core/quic_types.h"
19#include "net/third_party/quiche/src/quic/core/quic_versions.h"
vasilvvd88f1622019-11-04 13:50:53 -080020#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
vasilvv2b0ab242020-01-07 07:32:09 -080021#include "net/third_party/quiche/src/quic/platform/api/quic_optional.h"
vasilvv097f3722019-10-23 13:36:16 -070022#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
23#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_client_session.h"
24#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_server_session.h"
vasilvvd88f1622019-11-04 13:50:53 -080025#include "net/third_party/quiche/src/quic/quic_transport/quic_transport_stream.h"
vasilvv097f3722019-10-23 13:36:16 -070026#include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
27#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
vasilvvdfbd3df2019-11-01 11:58:43 -070028#include "net/third_party/quiche/src/quic/test_tools/quic_transport_test_tools.h"
vasilvv097f3722019-10-23 13:36:16 -070029#include "net/third_party/quiche/src/quic/test_tools/simulator/link.h"
30#include "net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint_base.h"
31#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h"
32#include "net/third_party/quiche/src/quic/test_tools/simulator/switch.h"
vasilvvd88f1622019-11-04 13:50:53 -080033#include "net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.h"
vasilvvda373d42020-01-16 12:36:27 -080034#include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
vasilvv097f3722019-10-23 13:36:16 -070035
36namespace quic {
37namespace test {
38namespace {
39
40using simulator::QuicEndpointBase;
41using simulator::Simulator;
vasilvvda373d42020-01-16 12:36:27 -080042using testing::_;
vasilvvd88f1622019-11-04 13:50:53 -080043using testing::Assign;
vasilvvda373d42020-01-16 12:36:27 -080044using testing::Eq;
vasilvv097f3722019-10-23 13:36:16 -070045
46url::Origin GetTestOrigin() {
47 constexpr char kTestOrigin[] = "https://test-origin.test";
48 GURL origin_url(kTestOrigin);
49 return url::Origin::Create(origin_url);
50}
51
52ParsedQuicVersionVector GetVersions() {
53 return {ParsedQuicVersion{PROTOCOL_TLS1_3, QUIC_VERSION_99}};
54}
55
56class QuicTransportEndpointBase : public QuicEndpointBase {
57 public:
58 QuicTransportEndpointBase(Simulator* simulator,
59 const std::string& name,
60 const std::string& peer_name,
61 Perspective perspective)
62 : QuicEndpointBase(simulator, name, peer_name) {
63 connection_ = std::make_unique<QuicConnection>(
64 TestConnectionId(0x10), simulator::GetAddressFromName(peer_name),
65 simulator, simulator->GetAlarmFactory(), &writer_,
66 /*owns_writer=*/false, perspective, GetVersions());
67 connection_->SetSelfAddress(simulator::GetAddressFromName(name));
vasilvv097f3722019-10-23 13:36:16 -070068 }
69};
70
71class QuicTransportClientEndpoint : public QuicTransportEndpointBase {
72 public:
73 QuicTransportClientEndpoint(Simulator* simulator,
74 const std::string& name,
75 const std::string& peer_name,
vasilvvec038f12020-01-07 11:58:08 -080076 const QuicConfig& config,
vasilvvd7692cd2019-12-06 08:06:31 -080077 url::Origin origin,
78 const std::string& path)
vasilvv097f3722019-10-23 13:36:16 -070079 : QuicTransportEndpointBase(simulator,
80 name,
81 peer_name,
82 Perspective::IS_CLIENT),
83 crypto_config_(crypto_test_utils::ProofVerifierForTesting()),
84 session_(connection_.get(),
85 nullptr,
vasilvvec038f12020-01-07 11:58:08 -080086 config,
vasilvv097f3722019-10-23 13:36:16 -070087 GetVersions(),
vasilvvd7692cd2019-12-06 08:06:31 -080088 GURL("quic-transport://test.example.com:50000" + path),
vasilvv097f3722019-10-23 13:36:16 -070089 &crypto_config_,
vasilvvdfbd3df2019-11-01 11:58:43 -070090 origin,
91 &visitor_) {
vasilvv097f3722019-10-23 13:36:16 -070092 session_.Initialize();
93 }
94
95 QuicTransportClientSession* session() { return &session_; }
vasilvvd88f1622019-11-04 13:50:53 -080096 MockClientVisitor* visitor() { return &visitor_; }
vasilvv097f3722019-10-23 13:36:16 -070097
98 private:
99 QuicCryptoClientConfig crypto_config_;
vasilvvdfbd3df2019-11-01 11:58:43 -0700100 MockClientVisitor visitor_;
vasilvv097f3722019-10-23 13:36:16 -0700101 QuicTransportClientSession session_;
102};
103
vasilvv097f3722019-10-23 13:36:16 -0700104class QuicTransportServerEndpoint : public QuicTransportEndpointBase {
105 public:
106 QuicTransportServerEndpoint(Simulator* simulator,
107 const std::string& name,
vasilvvd88f1622019-11-04 13:50:53 -0800108 const std::string& peer_name,
vasilvvec038f12020-01-07 11:58:08 -0800109 const QuicConfig& config,
vasilvvd88f1622019-11-04 13:50:53 -0800110 std::vector<url::Origin> accepted_origins)
vasilvv097f3722019-10-23 13:36:16 -0700111 : QuicTransportEndpointBase(simulator,
112 name,
113 peer_name,
114 Perspective::IS_SERVER),
115 crypto_config_(QuicCryptoServerConfig::TESTING,
116 QuicRandom::GetInstance(),
117 crypto_test_utils::ProofSourceForTesting(),
118 KeyExchangeSource::Default()),
119 compressed_certs_cache_(
120 QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
121 session_(connection_.get(),
vasilvvd88f1622019-11-04 13:50:53 -0800122 /*owns_connection=*/false,
vasilvv097f3722019-10-23 13:36:16 -0700123 nullptr,
vasilvvec038f12020-01-07 11:58:08 -0800124 config,
vasilvv097f3722019-10-23 13:36:16 -0700125 GetVersions(),
126 &crypto_config_,
127 &compressed_certs_cache_,
vasilvvd88f1622019-11-04 13:50:53 -0800128 accepted_origins) {
vasilvv097f3722019-10-23 13:36:16 -0700129 session_.Initialize();
130 }
131
132 QuicTransportServerSession* session() { return &session_; }
vasilvv097f3722019-10-23 13:36:16 -0700133
134 private:
135 QuicCryptoServerConfig crypto_config_;
136 QuicCompressedCertsCache compressed_certs_cache_;
vasilvvd88f1622019-11-04 13:50:53 -0800137 QuicTransportSimpleServerSession session_;
vasilvv097f3722019-10-23 13:36:16 -0700138};
139
vasilvvd88f1622019-11-04 13:50:53 -0800140std::unique_ptr<MockStreamVisitor> VisitorExpectingFin() {
141 auto visitor = std::make_unique<MockStreamVisitor>();
142 EXPECT_CALL(*visitor, OnFinRead());
143 return visitor;
144}
145
vasilvv097f3722019-10-23 13:36:16 -0700146constexpr QuicBandwidth kClientBandwidth =
147 QuicBandwidth::FromKBitsPerSecond(10000);
148constexpr QuicTime::Delta kClientPropagationDelay =
149 QuicTime::Delta::FromMilliseconds(2);
150constexpr QuicBandwidth kServerBandwidth =
151 QuicBandwidth::FromKBitsPerSecond(4000);
152constexpr QuicTime::Delta kServerPropagationDelay =
153 QuicTime::Delta::FromMilliseconds(50);
154const QuicTime::Delta kTransferTime =
155 kClientBandwidth.TransferTime(kMaxOutgoingPacketSize) +
156 kServerBandwidth.TransferTime(kMaxOutgoingPacketSize);
157const QuicTime::Delta kRtt =
158 (kClientPropagationDelay + kServerPropagationDelay + kTransferTime) * 2;
159const QuicByteCount kBdp = kRtt * kServerBandwidth;
160
vasilvvd88f1622019-11-04 13:50:53 -0800161constexpr QuicTime::Delta kDefaultTimeout = QuicTime::Delta::FromSeconds(3);
vasilvv097f3722019-10-23 13:36:16 -0700162
163class QuicTransportIntegrationTest : public QuicTest {
164 public:
165 QuicTransportIntegrationTest()
166 : switch_(&simulator_, "Switch", 8, 2 * kBdp) {}
167
vasilvvd7692cd2019-12-06 08:06:31 -0800168 void CreateDefaultEndpoints(const std::string& path) {
vasilvv097f3722019-10-23 13:36:16 -0700169 client_ = std::make_unique<QuicTransportClientEndpoint>(
vasilvvec038f12020-01-07 11:58:08 -0800170 &simulator_, "Client", "Server", client_config_, GetTestOrigin(), path);
vasilvvd88f1622019-11-04 13:50:53 -0800171 server_ = std::make_unique<QuicTransportServerEndpoint>(
vasilvvec038f12020-01-07 11:58:08 -0800172 &simulator_, "Server", "Client", server_config_, accepted_origins_);
vasilvv097f3722019-10-23 13:36:16 -0700173 }
174
175 void WireUpEndpoints() {
176 client_link_ = std::make_unique<simulator::SymmetricLink>(
177 client_.get(), switch_.port(1), kClientBandwidth,
178 kClientPropagationDelay);
179 server_link_ = std::make_unique<simulator::SymmetricLink>(
180 server_.get(), switch_.port(2), kServerBandwidth,
181 kServerPropagationDelay);
182 }
183
184 void RunHandshake() {
185 client_->session()->CryptoConnect();
186 bool result = simulator_.RunUntilOrTimeout(
187 [this]() {
188 return IsHandshakeDone(client_->session()) &&
189 IsHandshakeDone(server_->session());
190 },
vasilvvd88f1622019-11-04 13:50:53 -0800191 kDefaultTimeout);
vasilvv097f3722019-10-23 13:36:16 -0700192 EXPECT_TRUE(result);
193 }
194
195 protected:
196 template <class Session>
197 static bool IsHandshakeDone(const Session* session) {
198 return session->IsSessionReady() || session->error() != QUIC_NO_ERROR;
199 }
200
vasilvvec038f12020-01-07 11:58:08 -0800201 QuicConfig client_config_ = DefaultQuicConfig();
202 QuicConfig server_config_ = DefaultQuicConfig();
203
vasilvv097f3722019-10-23 13:36:16 -0700204 Simulator simulator_;
205 simulator::Switch switch_;
206 std::unique_ptr<simulator::SymmetricLink> client_link_;
207 std::unique_ptr<simulator::SymmetricLink> server_link_;
208
209 std::unique_ptr<QuicTransportClientEndpoint> client_;
210 std::unique_ptr<QuicTransportServerEndpoint> server_;
vasilvvd88f1622019-11-04 13:50:53 -0800211
212 std::vector<url::Origin> accepted_origins_ = {GetTestOrigin()};
vasilvv097f3722019-10-23 13:36:16 -0700213};
214
215TEST_F(QuicTransportIntegrationTest, SuccessfulHandshake) {
vasilvvd7692cd2019-12-06 08:06:31 -0800216 CreateDefaultEndpoints("/discard");
vasilvv097f3722019-10-23 13:36:16 -0700217 WireUpEndpoints();
vasilvv467b4222019-12-09 16:22:11 -0800218 EXPECT_CALL(*client_->visitor(), OnSessionReady());
vasilvv097f3722019-10-23 13:36:16 -0700219 RunHandshake();
220 EXPECT_TRUE(client_->session()->IsSessionReady());
221 EXPECT_TRUE(server_->session()->IsSessionReady());
222}
223
224TEST_F(QuicTransportIntegrationTest, OriginMismatch) {
vasilvvd88f1622019-11-04 13:50:53 -0800225 accepted_origins_ = {url::Origin::Create(GURL{"https://wrong-origin.test"})};
vasilvvd7692cd2019-12-06 08:06:31 -0800226 CreateDefaultEndpoints("/discard");
vasilvv097f3722019-10-23 13:36:16 -0700227 WireUpEndpoints();
vasilvv097f3722019-10-23 13:36:16 -0700228 RunHandshake();
229 // Wait until the client receives CONNECTION_CLOSE.
230 simulator_.RunUntilOrTimeout(
231 [this]() { return !client_->session()->connection()->connected(); },
vasilvvd88f1622019-11-04 13:50:53 -0800232 kDefaultTimeout);
vasilvv097f3722019-10-23 13:36:16 -0700233 EXPECT_TRUE(client_->session()->IsSessionReady());
234 EXPECT_FALSE(server_->session()->IsSessionReady());
235 EXPECT_FALSE(client_->session()->connection()->connected());
236 EXPECT_FALSE(server_->session()->connection()->connected());
bnca6cd6882019-11-27 08:46:01 -0800237 EXPECT_THAT(client_->session()->error(),
238 IsError(QUIC_TRANSPORT_INVALID_CLIENT_INDICATION));
239 EXPECT_THAT(server_->session()->error(),
240 IsError(QUIC_TRANSPORT_INVALID_CLIENT_INDICATION));
vasilvv097f3722019-10-23 13:36:16 -0700241}
242
vasilvvd88f1622019-11-04 13:50:53 -0800243TEST_F(QuicTransportIntegrationTest, SendOutgoingStreams) {
vasilvvd7692cd2019-12-06 08:06:31 -0800244 CreateDefaultEndpoints("/discard");
vasilvvd88f1622019-11-04 13:50:53 -0800245 WireUpEndpoints();
246 RunHandshake();
247
248 std::vector<QuicTransportStream*> streams;
249 for (int i = 0; i < 10; i++) {
250 QuicTransportStream* stream =
251 client_->session()->OpenOutgoingUnidirectionalStream();
252 ASSERT_TRUE(stream->Write("test"));
253 streams.push_back(stream);
254 }
255 ASSERT_TRUE(simulator_.RunUntilOrTimeout(
256 [this]() {
257 return server_->session()->GetNumOpenIncomingStreams() == 10;
258 },
259 kDefaultTimeout));
260
261 for (QuicTransportStream* stream : streams) {
262 ASSERT_TRUE(stream->SendFin());
263 }
264 ASSERT_TRUE(simulator_.RunUntilOrTimeout(
265 [this]() { return server_->session()->GetNumOpenIncomingStreams() == 0; },
266 kDefaultTimeout));
267}
268
269TEST_F(QuicTransportIntegrationTest, EchoBidirectionalStreams) {
vasilvvd7692cd2019-12-06 08:06:31 -0800270 CreateDefaultEndpoints("/echo");
vasilvvd88f1622019-11-04 13:50:53 -0800271 WireUpEndpoints();
272 RunHandshake();
273
274 QuicTransportStream* stream =
275 client_->session()->OpenOutgoingBidirectionalStream();
276 EXPECT_TRUE(stream->Write("Hello!"));
277
278 ASSERT_TRUE(simulator_.RunUntilOrTimeout(
279 [stream]() { return stream->ReadableBytes() == strlen("Hello!"); },
280 kDefaultTimeout));
281 std::string received;
282 EXPECT_EQ(stream->Read(&received), strlen("Hello!"));
283 EXPECT_EQ(received, "Hello!");
284
285 EXPECT_TRUE(stream->SendFin());
286 ASSERT_TRUE(simulator_.RunUntilOrTimeout(
287 [this]() { return server_->session()->GetNumOpenIncomingStreams() == 0; },
288 kDefaultTimeout));
289}
290
291TEST_F(QuicTransportIntegrationTest, EchoUnidirectionalStreams) {
vasilvvd7692cd2019-12-06 08:06:31 -0800292 CreateDefaultEndpoints("/echo");
vasilvvd88f1622019-11-04 13:50:53 -0800293 WireUpEndpoints();
294 RunHandshake();
295
296 // Send two streams, but only send FIN on the second one.
297 QuicTransportStream* stream1 =
298 client_->session()->OpenOutgoingUnidirectionalStream();
299 EXPECT_TRUE(stream1->Write("Stream One"));
300 QuicTransportStream* stream2 =
301 client_->session()->OpenOutgoingUnidirectionalStream();
302 EXPECT_TRUE(stream2->Write("Stream Two"));
303 EXPECT_TRUE(stream2->SendFin());
304
305 // Wait until a stream is received.
306 bool stream_received = false;
307 EXPECT_CALL(*client_->visitor(), OnIncomingUnidirectionalStreamAvailable())
308 .Times(2)
309 .WillRepeatedly(Assign(&stream_received, true));
310 ASSERT_TRUE(simulator_.RunUntilOrTimeout(
311 [&stream_received]() { return stream_received; }, kDefaultTimeout));
312
313 // Receive a reply stream and expect it to be the second one.
314 QuicTransportStream* reply =
315 client_->session()->AcceptIncomingUnidirectionalStream();
316 ASSERT_TRUE(reply != nullptr);
317 std::string buffer;
318 reply->set_visitor(VisitorExpectingFin());
319 EXPECT_GT(reply->Read(&buffer), 0u);
320 EXPECT_EQ(buffer, "Stream Two");
321
322 // Reset reply-related variables.
323 stream_received = false;
324 buffer = "";
325
326 // Send FIN on the first stream, and expect to receive it back.
327 EXPECT_TRUE(stream1->SendFin());
328 ASSERT_TRUE(simulator_.RunUntilOrTimeout(
329 [&stream_received]() { return stream_received; }, kDefaultTimeout));
330 reply = client_->session()->AcceptIncomingUnidirectionalStream();
331 ASSERT_TRUE(reply != nullptr);
332 reply->set_visitor(VisitorExpectingFin());
333 EXPECT_GT(reply->Read(&buffer), 0u);
334 EXPECT_EQ(buffer, "Stream One");
335}
336
vasilvv2b0ab242020-01-07 07:32:09 -0800337TEST_F(QuicTransportIntegrationTest, EchoDatagram) {
338 CreateDefaultEndpoints("/echo");
339 WireUpEndpoints();
340 RunHandshake();
341
342 client_->session()->datagram_queue()->SendOrQueueDatagram(
343 MemSliceFromString("test"));
344
345 bool datagram_received = false;
vasilvvda373d42020-01-16 12:36:27 -0800346 EXPECT_CALL(*client_->visitor(), OnDatagramReceived(Eq("test")))
vasilvv2b0ab242020-01-07 07:32:09 -0800347 .WillOnce(Assign(&datagram_received, true));
348 ASSERT_TRUE(simulator_.RunUntilOrTimeout(
349 [&datagram_received]() { return datagram_received; }, kDefaultTimeout));
vasilvv2b0ab242020-01-07 07:32:09 -0800350}
351
352// This test sets the datagram queue to an nearly-infinte queueing time, and
353// then sends 1000 datagrams. We expect to receive most of them back, since the
354// datagrams would be paced out by the congestion controller.
355TEST_F(QuicTransportIntegrationTest, EchoALotOfDatagrams) {
356 CreateDefaultEndpoints("/echo");
357 WireUpEndpoints();
358 RunHandshake();
359
360 // Set the datagrams to effectively never expire.
361 client_->session()->datagram_queue()->SetMaxTimeInQueue(10000 * kRtt);
362 for (int i = 0; i < 1000; i++) {
363 client_->session()->datagram_queue()->SendOrQueueDatagram(
364 MemSliceFromString(std::string(
365 client_->session()->GetGuaranteedLargestMessagePayload(), 'a')));
366 }
367
368 size_t received = 0;
vasilvvda373d42020-01-16 12:36:27 -0800369 EXPECT_CALL(*client_->visitor(), OnDatagramReceived(_))
370 .WillRepeatedly(
371 [&received](quiche::QuicheStringPiece /*datagram*/) { received++; });
vasilvv2b0ab242020-01-07 07:32:09 -0800372 ASSERT_TRUE(simulator_.RunUntilOrTimeout(
373 [this]() { return client_->session()->datagram_queue()->empty(); },
374 3 * kServerBandwidth.TransferTime(1000 * kMaxOutgoingPacketSize)));
375 // Allow extra round-trips for the final flight of datagrams to arrive back.
376 simulator_.RunFor(2 * kRtt);
377
378 EXPECT_GT(received, 500u);
379 EXPECT_LT(received, 1000u);
380}
381
vasilvvec038f12020-01-07 11:58:08 -0800382TEST_F(QuicTransportIntegrationTest, OutgoingStreamFlowControlBlocked) {
383 server_config_.SetMaxUnidirectionalStreamsToSend(4);
384 CreateDefaultEndpoints("/discard");
385 WireUpEndpoints();
386 RunHandshake();
387
388 QuicTransportStream* stream;
389 // Note that since we've already used one stream for client indication, we can
390 // only send three streams at once.
391 for (int i = 0; i < 3; i++) {
392 ASSERT_TRUE(client_->session()->CanOpenNextOutgoingUnidirectionalStream());
393 stream = client_->session()->OpenOutgoingUnidirectionalStream();
394 ASSERT_TRUE(stream != nullptr);
395 ASSERT_TRUE(stream->SendFin());
396 }
397 EXPECT_FALSE(client_->session()->CanOpenNextOutgoingUnidirectionalStream());
398
399 // Receiving FINs for the streams we've just opened will cause the server to
400 // let us open more streams.
401 bool can_create_new_stream = false;
402 EXPECT_CALL(*client_->visitor(), OnCanCreateNewOutgoingUnidirectionalStream())
403 .WillOnce(Assign(&can_create_new_stream, true));
404 ASSERT_TRUE(simulator_.RunUntilOrTimeout(
405 [&can_create_new_stream]() { return can_create_new_stream; },
406 kDefaultTimeout));
407 EXPECT_TRUE(client_->session()->CanOpenNextOutgoingUnidirectionalStream());
408}
409
vasilvv097f3722019-10-23 13:36:16 -0700410} // namespace
411} // namespace test
412} // namespace quic