1 // Copyright (c) 2018 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 #include "quiche/quic/core/quic_stream_id_manager.h"
5
6 #include <cstdint>
7 #include <string>
8 #include <utility>
9
10 #include "absl/strings/str_cat.h"
11 #include "quiche/quic/core/quic_constants.h"
12 #include "quiche/quic/core/quic_utils.h"
13 #include "quiche/quic/core/quic_versions.h"
14 #include "quiche/quic/platform/api/quic_expect_bug.h"
15 #include "quiche/quic/platform/api/quic_test.h"
16 #include "quiche/quic/test_tools/quic_stream_id_manager_peer.h"
17
18 using testing::_;
19 using testing::StrictMock;
20
21 namespace quic {
22 namespace test {
23 namespace {
24
25 class MockDelegate : public QuicStreamIdManager::DelegateInterface {
26 public:
27 MOCK_METHOD(void, SendMaxStreams,
28 (QuicStreamCount stream_count, bool unidirectional), (override));
29 MOCK_METHOD(bool, CanSendMaxStreams, (), (override));
30 };
31
32 struct TestParams {
TestParamsquic::test::__anon6bb801720111::TestParams33 TestParams(ParsedQuicVersion version, Perspective perspective,
34 bool is_unidirectional)
35 : version(version),
36 perspective(perspective),
37 is_unidirectional(is_unidirectional) {}
38
39 ParsedQuicVersion version;
40 Perspective perspective;
41 bool is_unidirectional;
42 };
43
44 // Used by ::testing::PrintToStringParamName().
PrintToString(const TestParams & p)45 std::string PrintToString(const TestParams& p) {
46 return absl::StrCat(
47 ParsedQuicVersionToString(p.version), "_",
48 (p.perspective == Perspective::IS_CLIENT ? "Client" : "Server"),
49 (p.is_unidirectional ? "Unidirectional" : "Bidirectional"));
50 }
51
GetTestParams()52 std::vector<TestParams> GetTestParams() {
53 std::vector<TestParams> params;
54 for (const ParsedQuicVersion& version : AllSupportedVersions()) {
55 if (!version.HasIetfQuicFrames()) {
56 continue;
57 }
58 for (Perspective perspective :
59 {Perspective::IS_CLIENT, Perspective::IS_SERVER}) {
60 for (bool is_unidirectional : {true, false}) {
61 params.push_back(TestParams(version, perspective, is_unidirectional));
62 }
63 }
64 }
65 return params;
66 }
67
68 class QuicStreamIdManagerTest : public QuicTestWithParam<TestParams> {
69 protected:
QuicStreamIdManagerTest()70 QuicStreamIdManagerTest()
71 : stream_id_manager_(&delegate_, IsUnidirectional(), perspective(),
72 GetParam().version, 0,
73 kDefaultMaxStreamsPerConnection) {
74 QUICHE_DCHECK(VersionHasIetfQuicFrames(transport_version()));
75 }
76
transport_version() const77 QuicTransportVersion transport_version() const {
78 return GetParam().version.transport_version;
79 }
80
81 // Returns the stream ID for the Nth incoming stream (created by the peer)
82 // of the corresponding directionality of this manager.
GetNthIncomingStreamId(int n)83 QuicStreamId GetNthIncomingStreamId(int n) {
84 return QuicUtils::StreamIdDelta(transport_version()) * n +
85 (IsUnidirectional()
86 ? QuicUtils::GetFirstUnidirectionalStreamId(
87 transport_version(),
88 QuicUtils::InvertPerspective(perspective()))
89 : QuicUtils::GetFirstBidirectionalStreamId(
90 transport_version(),
91 QuicUtils::InvertPerspective(perspective())));
92 }
93
IsUnidirectional()94 bool IsUnidirectional() { return GetParam().is_unidirectional; }
perspective()95 Perspective perspective() { return GetParam().perspective; }
96
97 StrictMock<MockDelegate> delegate_;
98 QuicStreamIdManager stream_id_manager_;
99 };
100
101 INSTANTIATE_TEST_SUITE_P(Tests, QuicStreamIdManagerTest,
102 ::testing::ValuesIn(GetTestParams()),
103 ::testing::PrintToStringParamName());
104
TEST_P(QuicStreamIdManagerTest,Initialization)105 TEST_P(QuicStreamIdManagerTest, Initialization) {
106 EXPECT_EQ(0u, stream_id_manager_.outgoing_max_streams());
107
108 EXPECT_EQ(kDefaultMaxStreamsPerConnection,
109 stream_id_manager_.incoming_actual_max_streams());
110 EXPECT_EQ(kDefaultMaxStreamsPerConnection,
111 stream_id_manager_.incoming_advertised_max_streams());
112 EXPECT_EQ(kDefaultMaxStreamsPerConnection,
113 stream_id_manager_.incoming_initial_max_open_streams());
114 }
115
116 // This test checks that the stream advertisement window is set to 1
117 // if the number of stream ids is 1. This is a special case in the code.
TEST_P(QuicStreamIdManagerTest,CheckMaxStreamsWindowForSingleStream)118 TEST_P(QuicStreamIdManagerTest, CheckMaxStreamsWindowForSingleStream) {
119 stream_id_manager_.SetMaxOpenIncomingStreams(1);
120 EXPECT_EQ(1u, stream_id_manager_.incoming_initial_max_open_streams());
121 EXPECT_EQ(1u, stream_id_manager_.incoming_actual_max_streams());
122 }
123
TEST_P(QuicStreamIdManagerTest,CheckMaxStreamsBadValuesOverMaxFailsOutgoing)124 TEST_P(QuicStreamIdManagerTest, CheckMaxStreamsBadValuesOverMaxFailsOutgoing) {
125 QuicStreamCount implementation_max = QuicUtils::GetMaxStreamCount();
126 // Ensure that the limit is less than the implementation maximum.
127 EXPECT_LT(stream_id_manager_.outgoing_max_streams(), implementation_max);
128
129 EXPECT_TRUE(
130 stream_id_manager_.MaybeAllowNewOutgoingStreams(implementation_max + 1));
131 // Should be pegged at the max.
132 EXPECT_EQ(implementation_max, stream_id_manager_.outgoing_max_streams());
133 }
134
135 // Check the case of the stream count in a STREAMS_BLOCKED frame is less than
136 // the count most recently advertised in a MAX_STREAMS frame.
TEST_P(QuicStreamIdManagerTest,ProcessStreamsBlockedOk)137 TEST_P(QuicStreamIdManagerTest, ProcessStreamsBlockedOk) {
138 QuicStreamCount stream_count =
139 stream_id_manager_.incoming_initial_max_open_streams();
140 QuicStreamsBlockedFrame frame(0, stream_count - 1, IsUnidirectional());
141 // We have notified peer about current max.
142 EXPECT_CALL(delegate_, SendMaxStreams(stream_count, IsUnidirectional()))
143 .Times(0);
144 std::string error_details;
145 EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details));
146 }
147
148 // Check the case of the stream count in a STREAMS_BLOCKED frame is equal to the
149 // count most recently advertised in a MAX_STREAMS frame. No MAX_STREAMS
150 // should be generated.
TEST_P(QuicStreamIdManagerTest,ProcessStreamsBlockedNoOp)151 TEST_P(QuicStreamIdManagerTest, ProcessStreamsBlockedNoOp) {
152 QuicStreamCount stream_count =
153 stream_id_manager_.incoming_initial_max_open_streams();
154 QuicStreamsBlockedFrame frame(0, stream_count, IsUnidirectional());
155 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
156 }
157
158 // Check the case of the stream count in a STREAMS_BLOCKED frame is greater than
159 // the count most recently advertised in a MAX_STREAMS frame. Expect a
160 // connection close with an error.
TEST_P(QuicStreamIdManagerTest,ProcessStreamsBlockedTooBig)161 TEST_P(QuicStreamIdManagerTest, ProcessStreamsBlockedTooBig) {
162 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
163 QuicStreamCount stream_count =
164 stream_id_manager_.incoming_initial_max_open_streams() + 1;
165 QuicStreamsBlockedFrame frame(0, stream_count, IsUnidirectional());
166 std::string error_details;
167 EXPECT_FALSE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details));
168 EXPECT_EQ(
169 error_details,
170 "StreamsBlockedFrame's stream count 101 exceeds incoming max stream 100");
171 }
172
173 // Same basic tests as above, but calls
174 // QuicStreamIdManager::MaybeIncreaseLargestPeerStreamId directly, avoiding the
175 // call chain. The intent is that if there is a problem, the following tests
176 // will point to either the stream ID manager or the call chain. They also
177 // provide specific, small scale, tests of a public QuicStreamIdManager method.
178 // First test make sure that streams with ids below the limit are accepted.
TEST_P(QuicStreamIdManagerTest,IsIncomingStreamIdValidBelowLimit)179 TEST_P(QuicStreamIdManagerTest, IsIncomingStreamIdValidBelowLimit) {
180 QuicStreamId stream_id = GetNthIncomingStreamId(
181 stream_id_manager_.incoming_actual_max_streams() - 2);
182 EXPECT_TRUE(
183 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id, nullptr));
184 }
185
186 // Accept a stream with an ID that equals the limit.
TEST_P(QuicStreamIdManagerTest,IsIncomingStreamIdValidAtLimit)187 TEST_P(QuicStreamIdManagerTest, IsIncomingStreamIdValidAtLimit) {
188 QuicStreamId stream_id = GetNthIncomingStreamId(
189 stream_id_manager_.incoming_actual_max_streams() - 1);
190 EXPECT_TRUE(
191 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id, nullptr));
192 }
193
194 // Close the connection if the id exceeds the limit.
TEST_P(QuicStreamIdManagerTest,IsIncomingStreamIdInValidAboveLimit)195 TEST_P(QuicStreamIdManagerTest, IsIncomingStreamIdInValidAboveLimit) {
196 QuicStreamId stream_id =
197 GetNthIncomingStreamId(stream_id_manager_.incoming_actual_max_streams());
198 std::string error_details;
199 EXPECT_FALSE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(
200 stream_id, &error_details));
201 EXPECT_EQ(error_details,
202 absl::StrCat("Stream id ", stream_id,
203 " would exceed stream count limit 100"));
204 }
205
TEST_P(QuicStreamIdManagerTest,OnStreamsBlockedFrame)206 TEST_P(QuicStreamIdManagerTest, OnStreamsBlockedFrame) {
207 // Get the current maximum allowed incoming stream count.
208 QuicStreamCount advertised_stream_count =
209 stream_id_manager_.incoming_advertised_max_streams();
210
211 QuicStreamsBlockedFrame frame;
212
213 frame.unidirectional = IsUnidirectional();
214
215 // If the peer is saying it's blocked on the stream count that
216 // we've advertised, it's a noop since the peer has the correct information.
217 frame.stream_count = advertised_stream_count;
218 std::string error_details;
219 EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details));
220
221 // If the peer is saying it's blocked on a stream count that is larger
222 // than what we've advertised, the connection should get closed.
223 frame.stream_count = advertised_stream_count + 1;
224 EXPECT_FALSE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details));
225 EXPECT_EQ(
226 error_details,
227 "StreamsBlockedFrame's stream count 101 exceeds incoming max stream 100");
228
229 // If the peer is saying it's blocked on a count that is less than
230 // our actual count, we send a MAX_STREAMS frame and update
231 // the advertised value.
232 // First, need to bump up the actual max so there is room for the MAX
233 // STREAMS frame to send a larger ID.
234 QuicStreamCount actual_stream_count =
235 stream_id_manager_.incoming_actual_max_streams();
236
237 // Closing a stream will result in the ability to initiate one more
238 // stream
239 stream_id_manager_.OnStreamClosed(
240 QuicStreamIdManagerPeer::GetFirstIncomingStreamId(&stream_id_manager_));
241 EXPECT_EQ(actual_stream_count + 1u,
242 stream_id_manager_.incoming_actual_max_streams());
243 EXPECT_EQ(stream_id_manager_.incoming_actual_max_streams(),
244 stream_id_manager_.incoming_advertised_max_streams() + 1u);
245
246 // Now simulate receiving a STREAMS_BLOCKED frame...
247 // Changing the actual maximum, above, forces a MAX_STREAMS frame to be
248 // sent, so the logic for that (SendMaxStreamsFrame(), etc) is tested.
249
250 // The STREAMS_BLOCKED frame contains the previous advertised count,
251 // not the one that the peer would have received as a result of the
252 // MAX_STREAMS sent earler.
253 frame.stream_count = advertised_stream_count;
254
255 EXPECT_CALL(delegate_, CanSendMaxStreams()).WillOnce(testing::Return(true));
256 EXPECT_CALL(delegate_,
257 SendMaxStreams(stream_id_manager_.incoming_actual_max_streams(),
258 IsUnidirectional()));
259
260 EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details));
261 // Check that the saved frame is correct.
262 EXPECT_EQ(stream_id_manager_.incoming_actual_max_streams(),
263 stream_id_manager_.incoming_advertised_max_streams());
264 }
265
TEST_P(QuicStreamIdManagerTest,OnStreamsBlockedFrameCantSend)266 TEST_P(QuicStreamIdManagerTest, OnStreamsBlockedFrameCantSend) {
267 // Get the current maximum allowed incoming stream count.
268 QuicStreamCount advertised_stream_count =
269 stream_id_manager_.incoming_advertised_max_streams();
270
271 QuicStreamsBlockedFrame frame;
272
273 frame.unidirectional = IsUnidirectional();
274
275 // First, need to bump up the actual max so there is room for the MAX
276 // STREAMS frame to send a larger ID.
277 QuicStreamCount actual_stream_count =
278 stream_id_manager_.incoming_actual_max_streams();
279
280 // Closing a stream will result in the ability to initiate one more
281 // stream
282 stream_id_manager_.OnStreamClosed(
283 QuicStreamIdManagerPeer::GetFirstIncomingStreamId(&stream_id_manager_));
284 EXPECT_EQ(actual_stream_count + 1u,
285 stream_id_manager_.incoming_actual_max_streams());
286 EXPECT_EQ(stream_id_manager_.incoming_actual_max_streams(),
287 stream_id_manager_.incoming_advertised_max_streams() + 1u);
288
289 // Now simulate receiving a STREAMS_BLOCKED frame...
290 // Changing the actual maximum, above, forces a MAX_STREAMS frame to be
291 // sent, so the logic for that (SendMaxStreamsFrame(), etc) is tested.
292
293 // The STREAMS_BLOCKED frame contains the previous advertised count,
294 // not the one that the peer would have received as a result of the
295 // MAX_STREAMS sent earler.
296 frame.stream_count = advertised_stream_count;
297
298 // Since the delegate returns false, no MAX_STREAMS frame should be sent,
299 // and the advertised limit should not increse.
300 EXPECT_CALL(delegate_, CanSendMaxStreams()).WillOnce(testing::Return(false));
301 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
302
303 const QuicStreamCount advertised_max_streams =
304 stream_id_manager_.incoming_advertised_max_streams();
305 std::string error_details;
306 EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details));
307 EXPECT_EQ(advertised_max_streams,
308 stream_id_manager_.incoming_advertised_max_streams());
309 }
310
TEST_P(QuicStreamIdManagerTest,GetNextOutgoingStream)311 TEST_P(QuicStreamIdManagerTest, GetNextOutgoingStream) {
312 // Number of streams we can open and the first one we should get when
313 // opening...
314 size_t number_of_streams = kDefaultMaxStreamsPerConnection;
315
316 EXPECT_TRUE(
317 stream_id_manager_.MaybeAllowNewOutgoingStreams(number_of_streams));
318
319 QuicStreamId stream_id = IsUnidirectional()
320 ? QuicUtils::GetFirstUnidirectionalStreamId(
321 transport_version(), perspective())
322 : QuicUtils::GetFirstBidirectionalStreamId(
323 transport_version(), perspective());
324
325 EXPECT_EQ(number_of_streams, stream_id_manager_.outgoing_max_streams());
326 while (number_of_streams) {
327 EXPECT_TRUE(stream_id_manager_.CanOpenNextOutgoingStream());
328 EXPECT_EQ(stream_id, stream_id_manager_.GetNextOutgoingStreamId());
329 stream_id += QuicUtils::StreamIdDelta(transport_version());
330 number_of_streams--;
331 }
332
333 // If we try to check that the next outgoing stream id is available it should
334 // fail.
335 EXPECT_FALSE(stream_id_manager_.CanOpenNextOutgoingStream());
336
337 // If we try to get the next id (above the limit), it should cause a quic-bug.
338 EXPECT_QUIC_BUG(
339 stream_id_manager_.GetNextOutgoingStreamId(),
340 "Attempt to allocate a new outgoing stream that would exceed the limit");
341 }
342
TEST_P(QuicStreamIdManagerTest,MaybeIncreaseLargestPeerStreamId)343 TEST_P(QuicStreamIdManagerTest, MaybeIncreaseLargestPeerStreamId) {
344 QuicStreamId max_stream_id = GetNthIncomingStreamId(
345 stream_id_manager_.incoming_actual_max_streams() - 1);
346 EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(max_stream_id,
347 nullptr));
348
349 QuicStreamId first_stream_id = GetNthIncomingStreamId(0);
350 EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(
351 first_stream_id, nullptr));
352 // A bad stream ID results in a closed connection.
353 std::string error_details;
354 EXPECT_FALSE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(
355 max_stream_id + QuicUtils::StreamIdDelta(transport_version()),
356 &error_details));
357 EXPECT_EQ(error_details,
358 absl::StrCat(
359 "Stream id ",
360 max_stream_id + QuicUtils::StreamIdDelta(transport_version()),
361 " would exceed stream count limit 100"));
362 }
363
TEST_P(QuicStreamIdManagerTest,MaxStreamsWindow)364 TEST_P(QuicStreamIdManagerTest, MaxStreamsWindow) {
365 // Open and then close a number of streams to get close to the threshold of
366 // sending a MAX_STREAM_FRAME.
367 int stream_count = stream_id_manager_.incoming_initial_max_open_streams() /
368 GetQuicFlag(quic_max_streams_window_divisor) -
369 1;
370
371 // Should not get a control-frame transmission since the peer should have
372 // "plenty" of stream IDs to use.
373 EXPECT_CALL(delegate_, CanSendMaxStreams()).Times(0);
374 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
375
376 // Get the first incoming stream ID to try and allocate.
377 QuicStreamId stream_id = GetNthIncomingStreamId(0);
378 size_t old_available_incoming_streams =
379 stream_id_manager_.available_incoming_streams();
380 auto i = stream_count;
381 while (i) {
382 EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id,
383 nullptr));
384
385 // This node should think that the peer believes it has one fewer
386 // stream it can create.
387 old_available_incoming_streams--;
388 EXPECT_EQ(old_available_incoming_streams,
389 stream_id_manager_.available_incoming_streams());
390
391 i--;
392 stream_id += QuicUtils::StreamIdDelta(transport_version());
393 }
394
395 // Now close them, still should get no MAX_STREAMS
396 stream_id = GetNthIncomingStreamId(0);
397 QuicStreamCount expected_actual_max =
398 stream_id_manager_.incoming_actual_max_streams();
399 QuicStreamCount expected_advertised_max_streams =
400 stream_id_manager_.incoming_advertised_max_streams();
401 while (stream_count) {
402 stream_id_manager_.OnStreamClosed(stream_id);
403 stream_count--;
404 stream_id += QuicUtils::StreamIdDelta(transport_version());
405 expected_actual_max++;
406 EXPECT_EQ(expected_actual_max,
407 stream_id_manager_.incoming_actual_max_streams());
408 // Advertised maximum should remain the same.
409 EXPECT_EQ(expected_advertised_max_streams,
410 stream_id_manager_.incoming_advertised_max_streams());
411 }
412
413 // This should not change.
414 EXPECT_EQ(old_available_incoming_streams,
415 stream_id_manager_.available_incoming_streams());
416
417 // Now whenever we close a stream we should get a MAX_STREAMS frame.
418 // Above code closed all the open streams, so we have to open/close
419 // EXPECT_CALL(delegate_,
420 // SendMaxStreams(stream_id_manager_.incoming_actual_max_streams(),
421 // IsUnidirectional()));
422 EXPECT_CALL(delegate_, CanSendMaxStreams()).WillOnce(testing::Return(true));
423 EXPECT_CALL(delegate_, SendMaxStreams(_, IsUnidirectional()));
424 EXPECT_TRUE(
425 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id, nullptr));
426 stream_id_manager_.OnStreamClosed(stream_id);
427 }
428
TEST_P(QuicStreamIdManagerTest,MaxStreamsWindowCantSend)429 TEST_P(QuicStreamIdManagerTest, MaxStreamsWindowCantSend) {
430 // Open and then close a number of streams to get close to the threshold of
431 // sending a MAX_STREAM_FRAME.
432 int stream_count = stream_id_manager_.incoming_initial_max_open_streams() /
433 GetQuicFlag(quic_max_streams_window_divisor) -
434 1;
435
436 // Should not get a control-frame transmission since the peer should have
437 // "plenty" of stream IDs to use.
438 EXPECT_CALL(delegate_, CanSendMaxStreams()).Times(0);
439 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
440
441 // Get the first incoming stream ID to try and allocate.
442 QuicStreamId stream_id = GetNthIncomingStreamId(0);
443 size_t old_available_incoming_streams =
444 stream_id_manager_.available_incoming_streams();
445 auto i = stream_count;
446 while (i) {
447 EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id,
448 nullptr));
449
450 // This node should think that the peer believes it has one fewer
451 // stream it can create.
452 old_available_incoming_streams--;
453 EXPECT_EQ(old_available_incoming_streams,
454 stream_id_manager_.available_incoming_streams());
455
456 i--;
457 stream_id += QuicUtils::StreamIdDelta(transport_version());
458 }
459
460 // Now close them, still should get no MAX_STREAMS
461 stream_id = GetNthIncomingStreamId(0);
462 QuicStreamCount expected_actual_max =
463 stream_id_manager_.incoming_actual_max_streams();
464 QuicStreamCount expected_advertised_max_streams =
465 stream_id_manager_.incoming_advertised_max_streams();
466 while (stream_count) {
467 stream_id_manager_.OnStreamClosed(stream_id);
468 stream_count--;
469 stream_id += QuicUtils::StreamIdDelta(transport_version());
470 expected_actual_max++;
471 EXPECT_EQ(expected_actual_max,
472 stream_id_manager_.incoming_actual_max_streams());
473 // Advertised maximum should remain the same.
474 EXPECT_EQ(expected_advertised_max_streams,
475 stream_id_manager_.incoming_advertised_max_streams());
476 }
477
478 // This should not change.
479 EXPECT_EQ(old_available_incoming_streams,
480 stream_id_manager_.available_incoming_streams());
481
482 // Now whenever we close a stream we should get a MAX_STREAMS frame,
483 // but since the delegate returns false, no MAX_STREAMS frame should
484 // be send and the advertised limit will not change.
485 // Above code closed all the open streams, so we have to open/close
486 EXPECT_CALL(delegate_, CanSendMaxStreams()).WillOnce(testing::Return(false));
487 EXPECT_CALL(delegate_, SendMaxStreams(_, IsUnidirectional())).Times(0);
488 EXPECT_TRUE(
489 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id, nullptr));
490 stream_id_manager_.OnStreamClosed(stream_id);
491 // Advertised maximum should remain the same.
492 EXPECT_EQ(expected_advertised_max_streams,
493 stream_id_manager_.incoming_advertised_max_streams());
494 }
495
TEST_P(QuicStreamIdManagerTest,MaxStreamsWindowStopsIncreasing)496 TEST_P(QuicStreamIdManagerTest, MaxStreamsWindowStopsIncreasing) {
497 // Verify that the incoming stream limit does not increase after
498 // StopIncreasingIncomingMaxStreams() is called, even when streams are closed.
499
500 QuicStreamId stream_count =
501 stream_id_manager_.incoming_initial_max_open_streams();
502 // Open up to the stream limit.
503 QuicStreamId stream_id = GetNthIncomingStreamId(0);
504 for (QuicStreamCount i = 0; i < stream_count; ++i) {
505 EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id,
506 nullptr));
507
508 stream_id += QuicUtils::StreamIdDelta(transport_version());
509 }
510
511 // Prevent max streams from increasing.
512 stream_id_manager_.StopIncreasingIncomingMaxStreams();
513
514 // Since the limit does not increase, a MAX_STREAMS frame will not be sent.
515 EXPECT_CALL(delegate_, CanSendMaxStreams()).Times(0);
516 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
517
518 // Now close them.
519 stream_id = GetNthIncomingStreamId(0);
520 QuicStreamCount expected_actual_max =
521 stream_id_manager_.incoming_actual_max_streams();
522 QuicStreamCount expected_advertised_max_streams =
523 stream_id_manager_.incoming_advertised_max_streams();
524 for (QuicStreamCount i = 0; i < stream_count; ++i) {
525 stream_id_manager_.OnStreamClosed(stream_id);
526 stream_id += QuicUtils::StreamIdDelta(transport_version());
527 // Limits should not change.
528 EXPECT_EQ(expected_actual_max,
529 stream_id_manager_.incoming_actual_max_streams());
530 EXPECT_EQ(expected_advertised_max_streams,
531 stream_id_manager_.incoming_advertised_max_streams());
532 }
533 }
534
TEST_P(QuicStreamIdManagerTest,StreamsBlockedEdgeConditions)535 TEST_P(QuicStreamIdManagerTest, StreamsBlockedEdgeConditions) {
536 QuicStreamsBlockedFrame frame;
537 frame.unidirectional = IsUnidirectional();
538
539 // Check that receipt of a STREAMS BLOCKED with stream-count = 0 does nothing
540 // when max_allowed_incoming_streams is 0.
541 EXPECT_CALL(delegate_, CanSendMaxStreams()).Times(0);
542 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
543 stream_id_manager_.SetMaxOpenIncomingStreams(0);
544 frame.stream_count = 0;
545 std::string error_details;
546 EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details));
547
548 // Check that receipt of a STREAMS BLOCKED with stream-count = 0 invokes a
549 // MAX STREAMS, count = 123, when the MaxOpen... is set to 123.
550 EXPECT_CALL(delegate_, CanSendMaxStreams()).WillOnce(testing::Return(true));
551 EXPECT_CALL(delegate_, SendMaxStreams(123u, IsUnidirectional()));
552 QuicStreamIdManagerPeer::set_incoming_actual_max_streams(&stream_id_manager_,
553 123);
554 frame.stream_count = 0;
555 EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details));
556 }
557
558 // Test that a MAX_STREAMS frame is generated when half the stream ids become
559 // available. This has a useful side effect of testing that when streams are
560 // closed, the number of available stream ids increases.
TEST_P(QuicStreamIdManagerTest,MaxStreamsSlidingWindow)561 TEST_P(QuicStreamIdManagerTest, MaxStreamsSlidingWindow) {
562 QuicStreamCount first_advert =
563 stream_id_manager_.incoming_advertised_max_streams();
564
565 // Open/close enough streams to shrink the window without causing a MAX
566 // STREAMS to be generated. The loop
567 // will make that many stream IDs available, so the last CloseStream should
568 // cause a MAX STREAMS frame to be generated.
569 int i =
570 static_cast<int>(stream_id_manager_.incoming_initial_max_open_streams() /
571 GetQuicFlag(quic_max_streams_window_divisor));
572 QuicStreamId id =
573 QuicStreamIdManagerPeer::GetFirstIncomingStreamId(&stream_id_manager_);
574 EXPECT_CALL(delegate_, CanSendMaxStreams()).WillOnce(testing::Return(true));
575 EXPECT_CALL(delegate_, SendMaxStreams(first_advert + i, IsUnidirectional()));
576 while (i) {
577 EXPECT_TRUE(
578 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(id, nullptr));
579 stream_id_manager_.OnStreamClosed(id);
580 i--;
581 id += QuicUtils::StreamIdDelta(transport_version());
582 }
583 }
584
TEST_P(QuicStreamIdManagerTest,NewStreamDoesNotExceedLimit)585 TEST_P(QuicStreamIdManagerTest, NewStreamDoesNotExceedLimit) {
586 EXPECT_TRUE(stream_id_manager_.MaybeAllowNewOutgoingStreams(100));
587
588 size_t stream_count = stream_id_manager_.outgoing_max_streams();
589 EXPECT_NE(0u, stream_count);
590
591 while (stream_count) {
592 EXPECT_TRUE(stream_id_manager_.CanOpenNextOutgoingStream());
593 stream_id_manager_.GetNextOutgoingStreamId();
594 stream_count--;
595 }
596
597 EXPECT_EQ(stream_id_manager_.outgoing_stream_count(),
598 stream_id_manager_.outgoing_max_streams());
599 // Create another, it should fail.
600 EXPECT_FALSE(stream_id_manager_.CanOpenNextOutgoingStream());
601 }
602
TEST_P(QuicStreamIdManagerTest,AvailableStreams)603 TEST_P(QuicStreamIdManagerTest, AvailableStreams) {
604 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(GetNthIncomingStreamId(3),
605 nullptr);
606
607 EXPECT_TRUE(stream_id_manager_.IsAvailableStream(GetNthIncomingStreamId(1)));
608 EXPECT_TRUE(stream_id_manager_.IsAvailableStream(GetNthIncomingStreamId(2)));
609 EXPECT_FALSE(stream_id_manager_.IsAvailableStream(GetNthIncomingStreamId(3)));
610 EXPECT_TRUE(stream_id_manager_.IsAvailableStream(GetNthIncomingStreamId(4)));
611 }
612
613 // Tests that if MaybeIncreaseLargestPeerStreamId is given an extremely
614 // large stream ID (larger than the limit) it is rejected.
615 // This is a regression for Chromium bugs 909987 and 910040
TEST_P(QuicStreamIdManagerTest,ExtremeMaybeIncreaseLargestPeerStreamId)616 TEST_P(QuicStreamIdManagerTest, ExtremeMaybeIncreaseLargestPeerStreamId) {
617 QuicStreamId too_big_stream_id = GetNthIncomingStreamId(
618 stream_id_manager_.incoming_actual_max_streams() + 20);
619
620 std::string error_details;
621 EXPECT_FALSE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(
622 too_big_stream_id, &error_details));
623 EXPECT_EQ(error_details,
624 absl::StrCat("Stream id ", too_big_stream_id,
625 " would exceed stream count limit 100"));
626 }
627
628 } // namespace
629 } // namespace test
630 } // namespace quic
631