blob: 689d4112d85ee85bb573262bac3904f2e4b6993b [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// 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 "net/third_party/quiche/src/quic/core/quic_stream_id_manager.h"
5
6#include <cstdint>
vasilvv872e7a32019-03-12 16:42:44 -07007#include <string>
QUICHE teama6ef0a62019-03-07 20:34:33 -05008#include <utility>
9
renjietang315428e2020-01-27 10:18:12 -080010#include "net/third_party/quiche/src/quic/core/quic_constants.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050011#include "net/third_party/quiche/src/quic/core/quic_utils.h"
dschinazi38cc1ee2020-02-28 14:33:58 -080012#include "net/third_party/quiche/src/quic/core/quic_versions.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050013#include "net/third_party/quiche/src/quic/platform/api/quic_expect_bug.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050014#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050015#include "net/third_party/quiche/src/quic/test_tools/quic_stream_id_manager_peer.h"
dmcardlecf0bfcf2019-12-13 08:08:21 -080016#include "net/third_party/quiche/src/common/platform/api/quiche_str_cat.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050017
18using testing::_;
QUICHE teama6ef0a62019-03-07 20:34:33 -050019using testing::StrictMock;
20
21namespace quic {
22namespace test {
23namespace {
24
rcha8b56e42019-09-20 10:41:48 -070025class MockDelegate : public QuicStreamIdManager::DelegateInterface {
QUICHE teama6ef0a62019-03-07 20:34:33 -050026 public:
wub713afae2020-04-27 07:48:31 -070027 MOCK_METHOD(void,
28 SendMaxStreams,
29 (QuicStreamCount stream_count, bool unidirectional),
30 (override));
QUICHE teama6ef0a62019-03-07 20:34:33 -050031};
32
rch9301d3c2019-09-20 14:30:48 -070033struct TestParams {
dschinazi38cc1ee2020-02-28 14:33:58 -080034 TestParams(ParsedQuicVersion version,
35 Perspective perspective,
36 bool is_unidirectional)
37 : version(version),
38 perspective(perspective),
39 is_unidirectional(is_unidirectional) {}
rch9301d3c2019-09-20 14:30:48 -070040
dschinazi38cc1ee2020-02-28 14:33:58 -080041 ParsedQuicVersion version;
rch9301d3c2019-09-20 14:30:48 -070042 Perspective perspective;
43 bool is_unidirectional;
44};
45
46// Used by ::testing::PrintToStringParamName().
47std::string PrintToString(const TestParams& p) {
dmcardlecf0bfcf2019-12-13 08:08:21 -080048 return quiche::QuicheStrCat(
dschinazi38cc1ee2020-02-28 14:33:58 -080049 ParsedQuicVersionToString(p.version), "_",
rch9301d3c2019-09-20 14:30:48 -070050 (p.perspective == Perspective::IS_CLIENT ? "Client" : "Server"),
51 (p.is_unidirectional ? "Unidirectional" : "Bidirectional"));
52}
53
54std::vector<TestParams> GetTestParams() {
55 std::vector<TestParams> params;
dschinazi38cc1ee2020-02-28 14:33:58 -080056 for (const ParsedQuicVersion& version : AllSupportedVersions()) {
57 if (!version.HasIetfQuicFrames()) {
58 continue;
59 }
60 for (Perspective perspective :
61 {Perspective::IS_CLIENT, Perspective::IS_SERVER}) {
62 for (bool is_unidirectional : {true, false}) {
63 params.push_back(TestParams(version, perspective, is_unidirectional));
64 }
rch9301d3c2019-09-20 14:30:48 -070065 }
66 }
67 return params;
68}
69
70class QuicStreamIdManagerTest : public QuicTestWithParam<TestParams> {
QUICHE teama6ef0a62019-03-07 20:34:33 -050071 protected:
rch9301d3c2019-09-20 14:30:48 -070072 QuicStreamIdManagerTest()
rcha8b56e42019-09-20 10:41:48 -070073 : stream_id_manager_(&delegate_,
rch9301d3c2019-09-20 14:30:48 -070074 IsUnidirectional(),
75 perspective(),
renjietang40038f52020-04-08 11:30:31 -070076 GetParam().version,
renjietang315428e2020-01-27 10:18:12 -080077 0,
rch9301d3c2019-09-20 14:30:48 -070078 kDefaultMaxStreamsPerConnection) {
79 DCHECK(VersionHasIetfQuicFrames(transport_version()));
80 }
QUICHE teama6ef0a62019-03-07 20:34:33 -050081
dschinazi38cc1ee2020-02-28 14:33:58 -080082 QuicTransportVersion transport_version() const {
83 return GetParam().version.transport_version;
84 }
QUICHE teama6ef0a62019-03-07 20:34:33 -050085
rch9301d3c2019-09-20 14:30:48 -070086 // Returns the stream ID for the Nth incoming stream (created by the peer)
87 // of the corresponding directionality of this manager.
88 QuicStreamId GetNthIncomingStreamId(int n) {
renjietang01e6f382020-04-02 13:36:14 -070089 return QuicUtils::StreamIdDelta(transport_version()) * n +
rch9301d3c2019-09-20 14:30:48 -070090 (IsUnidirectional()
91 ? QuicUtils::GetFirstUnidirectionalStreamId(
92 transport_version(),
93 QuicUtils::InvertPerspective(perspective()))
94 : QuicUtils::GetFirstBidirectionalStreamId(
95 transport_version(),
96 QuicUtils::InvertPerspective(perspective())));
QUICHE teama6ef0a62019-03-07 20:34:33 -050097 }
98
rch9301d3c2019-09-20 14:30:48 -070099 bool IsUnidirectional() { return GetParam().is_unidirectional; }
100 Perspective perspective() { return GetParam().perspective; }
fkastenholz3c4eabf2019-04-22 07:49:59 -0700101
rcha8b56e42019-09-20 10:41:48 -0700102 StrictMock<MockDelegate> delegate_;
103 QuicStreamIdManager stream_id_manager_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500104};
105
dschinazi142051a2019-09-18 18:17:29 -0700106INSTANTIATE_TEST_SUITE_P(Tests,
rch9301d3c2019-09-20 14:30:48 -0700107 QuicStreamIdManagerTest,
108 ::testing::ValuesIn(GetTestParams()),
dschinazi142051a2019-09-18 18:17:29 -0700109 ::testing::PrintToStringParamName());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500110
rch9301d3c2019-09-20 14:30:48 -0700111TEST_P(QuicStreamIdManagerTest, Initialization) {
renjietang315428e2020-01-27 10:18:12 -0800112 EXPECT_EQ(0u, stream_id_manager_.outgoing_max_streams());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700113
QUICHE teama6ef0a62019-03-07 20:34:33 -0500114 EXPECT_EQ(kDefaultMaxStreamsPerConnection,
rcha8b56e42019-09-20 10:41:48 -0700115 stream_id_manager_.incoming_actual_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500116 EXPECT_EQ(kDefaultMaxStreamsPerConnection,
rcha8b56e42019-09-20 10:41:48 -0700117 stream_id_manager_.incoming_advertised_max_streams());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700118 EXPECT_EQ(kDefaultMaxStreamsPerConnection,
rcha8b56e42019-09-20 10:41:48 -0700119 stream_id_manager_.incoming_initial_max_open_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500120}
121
122// This test checks that the stream advertisement window is set to 1
123// if the number of stream ids is 1. This is a special case in the code.
rch9301d3c2019-09-20 14:30:48 -0700124TEST_P(QuicStreamIdManagerTest, CheckMaxStreamsWindowForSingleStream) {
rcha8b56e42019-09-20 10:41:48 -0700125 stream_id_manager_.SetMaxOpenIncomingStreams(1);
126 EXPECT_EQ(1u, stream_id_manager_.incoming_initial_max_open_streams());
127 EXPECT_EQ(1u, stream_id_manager_.incoming_actual_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500128}
129
rch9301d3c2019-09-20 14:30:48 -0700130TEST_P(QuicStreamIdManagerTest, CheckMaxStreamsBadValuesOverMaxFailsOutgoing) {
renjietangb885a122020-03-20 08:24:16 -0700131 QuicStreamCount implementation_max = QuicUtils::GetMaxStreamCount();
fkastenholz3c4eabf2019-04-22 07:49:59 -0700132 // Ensure that the limit is less than the implementation maximum.
rcha8b56e42019-09-20 10:41:48 -0700133 EXPECT_LT(stream_id_manager_.outgoing_max_streams(), implementation_max);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700134
renjietangab9039a2020-03-30 14:53:19 -0700135 EXPECT_TRUE(
136 stream_id_manager_.MaybeAllowNewOutgoingStreams(implementation_max + 1));
fkastenholz3c4eabf2019-04-22 07:49:59 -0700137 // Should be pegged at the max.
rcha8b56e42019-09-20 10:41:48 -0700138 EXPECT_EQ(implementation_max, stream_id_manager_.outgoing_max_streams());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700139}
140
fkastenholz3c4eabf2019-04-22 07:49:59 -0700141// Check the case of the stream count in a STREAMS_BLOCKED frame is less than
fayang2c25f512020-06-10 11:20:16 -0700142// the count most recently advertised in a MAX_STREAMS frame.
rch9301d3c2019-09-20 14:30:48 -0700143TEST_P(QuicStreamIdManagerTest, ProcessStreamsBlockedOk) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700144 QuicStreamCount stream_count =
rcha8b56e42019-09-20 10:41:48 -0700145 stream_id_manager_.incoming_initial_max_open_streams();
rch9301d3c2019-09-20 14:30:48 -0700146 QuicStreamsBlockedFrame frame(0, stream_count - 1, IsUnidirectional());
fayang2c25f512020-06-10 11:20:16 -0700147 if (GetQuicReloadableFlag(quic_stop_sending_duplicate_max_streams)) {
148 // We have notified peer about current max.
149 EXPECT_CALL(delegate_, SendMaxStreams(stream_count, IsUnidirectional()))
150 .Times(0);
151 } else {
152 EXPECT_CALL(delegate_, SendMaxStreams(stream_count, IsUnidirectional()));
153 }
renjietang7133ea92020-04-01 12:49:36 -0700154 std::string error_details;
155 EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500156}
157
fkastenholz3c4eabf2019-04-22 07:49:59 -0700158// Check the case of the stream count in a STREAMS_BLOCKED frame is equal to the
159// count most recently advertised in a MAX_STREAMS frame. No MAX_STREAMS
160// should be generated.
rch9301d3c2019-09-20 14:30:48 -0700161TEST_P(QuicStreamIdManagerTest, ProcessStreamsBlockedNoOp) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700162 QuicStreamCount stream_count =
rcha8b56e42019-09-20 10:41:48 -0700163 stream_id_manager_.incoming_initial_max_open_streams();
rch9301d3c2019-09-20 14:30:48 -0700164 QuicStreamsBlockedFrame frame(0, stream_count, IsUnidirectional());
rcha8b56e42019-09-20 10:41:48 -0700165 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500166}
167
fkastenholz3c4eabf2019-04-22 07:49:59 -0700168// Check the case of the stream count in a STREAMS_BLOCKED frame is greater than
169// the count most recently advertised in a MAX_STREAMS frame. Expect a
QUICHE teama6ef0a62019-03-07 20:34:33 -0500170// connection close with an error.
rch9301d3c2019-09-20 14:30:48 -0700171TEST_P(QuicStreamIdManagerTest, ProcessStreamsBlockedTooBig) {
rcha8b56e42019-09-20 10:41:48 -0700172 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700173 QuicStreamCount stream_count =
rcha8b56e42019-09-20 10:41:48 -0700174 stream_id_manager_.incoming_initial_max_open_streams() + 1;
rch9301d3c2019-09-20 14:30:48 -0700175 QuicStreamsBlockedFrame frame(0, stream_count, IsUnidirectional());
renjietang7133ea92020-04-01 12:49:36 -0700176 std::string error_details;
177 EXPECT_FALSE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details));
178 EXPECT_EQ(
179 error_details,
180 "StreamsBlockedFrame's stream count 101 exceeds incoming max stream 100");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500181}
182
183// Same basic tests as above, but calls
184// QuicStreamIdManager::MaybeIncreaseLargestPeerStreamId directly, avoiding the
185// call chain. The intent is that if there is a problem, the following tests
186// will point to either the stream ID manager or the call chain. They also
187// provide specific, small scale, tests of a public QuicStreamIdManager method.
188// First test make sure that streams with ids below the limit are accepted.
rch9301d3c2019-09-20 14:30:48 -0700189TEST_P(QuicStreamIdManagerTest, IsIncomingStreamIdValidBelowLimit) {
190 QuicStreamId stream_id = GetNthIncomingStreamId(
191 stream_id_manager_.incoming_actual_max_streams() - 2);
renjietang7133ea92020-04-01 12:49:36 -0700192 EXPECT_TRUE(
193 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id, nullptr));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500194}
195
196// Accept a stream with an ID that equals the limit.
rch9301d3c2019-09-20 14:30:48 -0700197TEST_P(QuicStreamIdManagerTest, IsIncomingStreamIdValidAtLimit) {
198 QuicStreamId stream_id = GetNthIncomingStreamId(
199 stream_id_manager_.incoming_actual_max_streams() - 1);
renjietang7133ea92020-04-01 12:49:36 -0700200 EXPECT_TRUE(
201 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id, nullptr));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500202}
203
204// Close the connection if the id exceeds the limit.
rch9301d3c2019-09-20 14:30:48 -0700205TEST_P(QuicStreamIdManagerTest, IsIncomingStreamIdInValidAboveLimit) {
206 QuicStreamId stream_id =
207 GetNthIncomingStreamId(stream_id_manager_.incoming_actual_max_streams());
renjietang7133ea92020-04-01 12:49:36 -0700208 std::string error_details;
209 EXPECT_FALSE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(
210 stream_id, &error_details));
211 EXPECT_EQ(error_details,
212 quiche::QuicheStrCat("Stream id ", stream_id,
213 " would exceed stream count limit 100"));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500214}
215
rch9301d3c2019-09-20 14:30:48 -0700216TEST_P(QuicStreamIdManagerTest, OnStreamsBlockedFrame) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700217 // Get the current maximum allowed incoming stream count.
218 QuicStreamCount advertised_stream_count =
rcha8b56e42019-09-20 10:41:48 -0700219 stream_id_manager_.incoming_advertised_max_streams();
220
fkastenholz3c4eabf2019-04-22 07:49:59 -0700221 QuicStreamsBlockedFrame frame;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500222
rch9301d3c2019-09-20 14:30:48 -0700223 frame.unidirectional = IsUnidirectional();
fkastenholz3c4eabf2019-04-22 07:49:59 -0700224
225 // If the peer is saying it's blocked on the stream count that
QUICHE teama6ef0a62019-03-07 20:34:33 -0500226 // we've advertised, it's a noop since the peer has the correct information.
fkastenholz3c4eabf2019-04-22 07:49:59 -0700227 frame.stream_count = advertised_stream_count;
renjietang7133ea92020-04-01 12:49:36 -0700228 std::string error_details;
229 EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500230
fkastenholz3c4eabf2019-04-22 07:49:59 -0700231 // If the peer is saying it's blocked on a stream count that is larger
QUICHE teama6ef0a62019-03-07 20:34:33 -0500232 // than what we've advertised, the connection should get closed.
fkastenholz3c4eabf2019-04-22 07:49:59 -0700233 frame.stream_count = advertised_stream_count + 1;
renjietang7133ea92020-04-01 12:49:36 -0700234 EXPECT_FALSE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details));
235 EXPECT_EQ(
236 error_details,
237 "StreamsBlockedFrame's stream count 101 exceeds incoming max stream 100");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500238
fkastenholz3c4eabf2019-04-22 07:49:59 -0700239 // If the peer is saying it's blocked on a count that is less than
240 // our actual count, we send a MAX_STREAMS frame and update
QUICHE teama6ef0a62019-03-07 20:34:33 -0500241 // the advertised value.
242 // First, need to bump up the actual max so there is room for the MAX
fkastenholz3c4eabf2019-04-22 07:49:59 -0700243 // STREAMS frame to send a larger ID.
244 QuicStreamCount actual_stream_count =
rcha8b56e42019-09-20 10:41:48 -0700245 stream_id_manager_.incoming_actual_max_streams();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500246
fkastenholz3c4eabf2019-04-22 07:49:59 -0700247 // Closing a stream will result in the ability to initiate one more
248 // stream
rcha8b56e42019-09-20 10:41:48 -0700249 stream_id_manager_.OnStreamClosed(
250 QuicStreamIdManagerPeer::GetFirstIncomingStreamId(&stream_id_manager_));
fkastenholzd035fc32019-04-23 12:24:02 -0700251 EXPECT_EQ(actual_stream_count + 1u,
rcha8b56e42019-09-20 10:41:48 -0700252 stream_id_manager_.incoming_actual_max_streams());
253 EXPECT_EQ(stream_id_manager_.incoming_actual_max_streams(),
254 stream_id_manager_.incoming_advertised_max_streams() + 1u);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700255
256 // Now simulate receiving a STREAMS_BLOCKED frame...
257 // Changing the actual maximum, above, forces a MAX_STREAMS frame to be
258 // sent, so the logic for that (SendMaxStreamsFrame(), etc) is tested.
259
260 // The STREAMS_BLOCKED frame contains the previous advertised count,
261 // not the one that the peer would have received as a result of the
262 // MAX_STREAMS sent earler.
263 frame.stream_count = advertised_stream_count;
264
rcha8b56e42019-09-20 10:41:48 -0700265 EXPECT_CALL(delegate_,
266 SendMaxStreams(stream_id_manager_.incoming_actual_max_streams(),
rch9301d3c2019-09-20 14:30:48 -0700267 IsUnidirectional()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500268
renjietang7133ea92020-04-01 12:49:36 -0700269 EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details));
fkastenholz3c4eabf2019-04-22 07:49:59 -0700270 // Check that the saved frame is correct.
rcha8b56e42019-09-20 10:41:48 -0700271 EXPECT_EQ(stream_id_manager_.incoming_actual_max_streams(),
272 stream_id_manager_.incoming_advertised_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500273}
274
rch9301d3c2019-09-20 14:30:48 -0700275TEST_P(QuicStreamIdManagerTest, GetNextOutgoingStream) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500276 // Number of streams we can open and the first one we should get when
277 // opening...
renjietang7fc869e2019-08-14 11:02:42 -0700278 size_t number_of_streams = kDefaultMaxStreamsPerConnection;
fkastenholz56055be2019-09-17 11:17:37 -0700279
renjietangab9039a2020-03-30 14:53:19 -0700280 EXPECT_TRUE(
281 stream_id_manager_.MaybeAllowNewOutgoingStreams(number_of_streams));
rcha8b56e42019-09-20 10:41:48 -0700282
renjietang7b51ec02020-04-07 16:07:09 -0700283 QuicStreamId stream_id = IsUnidirectional()
284 ? QuicUtils::GetFirstUnidirectionalStreamId(
285 transport_version(), perspective())
286 : QuicUtils::GetFirstBidirectionalStreamId(
287 transport_version(), perspective());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500288
rcha8b56e42019-09-20 10:41:48 -0700289 EXPECT_EQ(number_of_streams, stream_id_manager_.outgoing_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500290 while (number_of_streams) {
rcha8b56e42019-09-20 10:41:48 -0700291 EXPECT_TRUE(stream_id_manager_.CanOpenNextOutgoingStream());
292 EXPECT_EQ(stream_id, stream_id_manager_.GetNextOutgoingStreamId());
renjietang01e6f382020-04-02 13:36:14 -0700293 stream_id += QuicUtils::StreamIdDelta(transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500294 number_of_streams--;
295 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500296
297 // If we try to check that the next outgoing stream id is available it should
fayang769172b2020-03-19 14:27:39 -0700298 // fail.
rcha8b56e42019-09-20 10:41:48 -0700299 EXPECT_FALSE(stream_id_manager_.CanOpenNextOutgoingStream());
300
QUICHE teama6ef0a62019-03-07 20:34:33 -0500301 // If we try to get the next id (above the limit), it should cause a quic-bug.
302 EXPECT_QUIC_BUG(
rcha8b56e42019-09-20 10:41:48 -0700303 stream_id_manager_.GetNextOutgoingStreamId(),
fkastenholz3c4eabf2019-04-22 07:49:59 -0700304 "Attempt to allocate a new outgoing stream that would exceed the limit");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500305}
306
rch9301d3c2019-09-20 14:30:48 -0700307TEST_P(QuicStreamIdManagerTest, MaybeIncreaseLargestPeerStreamId) {
308 QuicStreamId max_stream_id = GetNthIncomingStreamId(
309 stream_id_manager_.incoming_actual_max_streams() - 1);
renjietang7133ea92020-04-01 12:49:36 -0700310 EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(max_stream_id,
311 nullptr));
fkastenholz3c4eabf2019-04-22 07:49:59 -0700312
rch9301d3c2019-09-20 14:30:48 -0700313 QuicStreamId first_stream_id = GetNthIncomingStreamId(0);
renjietang7133ea92020-04-01 12:49:36 -0700314 EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(
315 first_stream_id, nullptr));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500316 // A bad stream ID results in a closed connection.
renjietang7133ea92020-04-01 12:49:36 -0700317 std::string error_details;
rcha8b56e42019-09-20 10:41:48 -0700318 EXPECT_FALSE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(
renjietang01e6f382020-04-02 13:36:14 -0700319 max_stream_id + QuicUtils::StreamIdDelta(transport_version()),
320 &error_details));
321 EXPECT_EQ(error_details,
322 quiche::QuicheStrCat(
323 "Stream id ",
324 max_stream_id + QuicUtils::StreamIdDelta(transport_version()),
325 " would exceed stream count limit 100"));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500326}
327
rch9301d3c2019-09-20 14:30:48 -0700328TEST_P(QuicStreamIdManagerTest, MaxStreamsWindow) {
renjietang22305852020-04-06 15:05:18 -0700329 // Open and then close a number of streams to get close to the threshold of
330 // sending a MAX_STREAM_FRAME.
331 int stream_count = stream_id_manager_.incoming_initial_max_open_streams() /
renjietang53570412020-04-07 06:32:17 -0700332 GetQuicFlag(FLAGS_quic_max_streams_window_divisor) -
renjietang22305852020-04-06 15:05:18 -0700333 1;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500334
335 // Should not get a control-frame transmission since the peer should have
336 // "plenty" of stream IDs to use.
rcha8b56e42019-09-20 10:41:48 -0700337 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700338
339 // Get the first incoming stream ID to try and allocate.
rch9301d3c2019-09-20 14:30:48 -0700340 QuicStreamId stream_id = GetNthIncomingStreamId(0);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500341 size_t old_available_incoming_streams =
rcha8b56e42019-09-20 10:41:48 -0700342 stream_id_manager_.available_incoming_streams();
renjietang22305852020-04-06 15:05:18 -0700343 auto i = stream_count;
344 while (i) {
renjietang7133ea92020-04-01 12:49:36 -0700345 EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id,
346 nullptr));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500347
fkastenholz3c4eabf2019-04-22 07:49:59 -0700348 // This node should think that the peer believes it has one fewer
349 // stream it can create.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500350 old_available_incoming_streams--;
351 EXPECT_EQ(old_available_incoming_streams,
rcha8b56e42019-09-20 10:41:48 -0700352 stream_id_manager_.available_incoming_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500353
renjietang22305852020-04-06 15:05:18 -0700354 i--;
renjietang01e6f382020-04-02 13:36:14 -0700355 stream_id += QuicUtils::StreamIdDelta(transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500356 }
357
fkastenholz3c4eabf2019-04-22 07:49:59 -0700358 // Now close them, still should get no MAX_STREAMS
rch9301d3c2019-09-20 14:30:48 -0700359 stream_id = GetNthIncomingStreamId(0);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700360 QuicStreamCount expected_actual_max =
rcha8b56e42019-09-20 10:41:48 -0700361 stream_id_manager_.incoming_actual_max_streams();
fkastenholz3c4eabf2019-04-22 07:49:59 -0700362 QuicStreamCount expected_advertised_max_streams =
rcha8b56e42019-09-20 10:41:48 -0700363 stream_id_manager_.incoming_advertised_max_streams();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500364 while (stream_count) {
rcha8b56e42019-09-20 10:41:48 -0700365 stream_id_manager_.OnStreamClosed(stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500366 stream_count--;
renjietang01e6f382020-04-02 13:36:14 -0700367 stream_id += QuicUtils::StreamIdDelta(transport_version());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700368 expected_actual_max++;
369 EXPECT_EQ(expected_actual_max,
rcha8b56e42019-09-20 10:41:48 -0700370 stream_id_manager_.incoming_actual_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500371 // Advertised maximum should remain the same.
fkastenholz3c4eabf2019-04-22 07:49:59 -0700372 EXPECT_EQ(expected_advertised_max_streams,
rcha8b56e42019-09-20 10:41:48 -0700373 stream_id_manager_.incoming_advertised_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500374 }
375
376 // This should not change.
377 EXPECT_EQ(old_available_incoming_streams,
rcha8b56e42019-09-20 10:41:48 -0700378 stream_id_manager_.available_incoming_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500379
fkastenholz3c4eabf2019-04-22 07:49:59 -0700380 // Now whenever we close a stream we should get a MAX_STREAMS frame.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500381 // Above code closed all the open streams, so we have to open/close
rcha8b56e42019-09-20 10:41:48 -0700382 // EXPECT_CALL(delegate_,
383 // SendMaxStreams(stream_id_manager_.incoming_actual_max_streams(),
rch9301d3c2019-09-20 14:30:48 -0700384 // IsUnidirectional()));
385 EXPECT_CALL(delegate_, SendMaxStreams(_, IsUnidirectional()));
renjietang7133ea92020-04-01 12:49:36 -0700386 EXPECT_TRUE(
387 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id, nullptr));
rcha8b56e42019-09-20 10:41:48 -0700388 stream_id_manager_.OnStreamClosed(stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500389}
390
rch9301d3c2019-09-20 14:30:48 -0700391TEST_P(QuicStreamIdManagerTest, StreamsBlockedEdgeConditions) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700392 QuicStreamsBlockedFrame frame;
rch9301d3c2019-09-20 14:30:48 -0700393 frame.unidirectional = IsUnidirectional();
fkastenholz3c4eabf2019-04-22 07:49:59 -0700394
395 // Check that receipt of a STREAMS BLOCKED with stream-count = 0 does nothing
396 // when max_allowed_incoming_streams is 0.
rcha8b56e42019-09-20 10:41:48 -0700397 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
rcha8b56e42019-09-20 10:41:48 -0700398 stream_id_manager_.SetMaxOpenIncomingStreams(0);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700399 frame.stream_count = 0;
renjietang7133ea92020-04-01 12:49:36 -0700400 std::string error_details;
401 EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details));
fkastenholz3c4eabf2019-04-22 07:49:59 -0700402
403 // Check that receipt of a STREAMS BLOCKED with stream-count = 0 invokes a
404 // MAX STREAMS, count = 123, when the MaxOpen... is set to 123.
rch9301d3c2019-09-20 14:30:48 -0700405 EXPECT_CALL(delegate_, SendMaxStreams(123u, IsUnidirectional()));
fayang2c25f512020-06-10 11:20:16 -0700406 if (GetQuicReloadableFlag(quic_stop_sending_duplicate_max_streams)) {
407 QuicStreamIdManagerPeer::set_incoming_actual_max_streams(
408 &stream_id_manager_, 123);
409 } else {
410 stream_id_manager_.SetMaxOpenIncomingStreams(123);
411 }
fkastenholz3c4eabf2019-04-22 07:49:59 -0700412 frame.stream_count = 0;
renjietang7133ea92020-04-01 12:49:36 -0700413 EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame, &error_details));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500414}
415
fkastenholz3c4eabf2019-04-22 07:49:59 -0700416// Test that a MAX_STREAMS frame is generated when half the stream ids become
QUICHE teama6ef0a62019-03-07 20:34:33 -0500417// available. This has a useful side effect of testing that when streams are
418// closed, the number of available stream ids increases.
rch9301d3c2019-09-20 14:30:48 -0700419TEST_P(QuicStreamIdManagerTest, MaxStreamsSlidingWindow) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700420 QuicStreamCount first_advert =
rcha8b56e42019-09-20 10:41:48 -0700421 stream_id_manager_.incoming_advertised_max_streams();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500422
fkastenholz3c4eabf2019-04-22 07:49:59 -0700423 // Open/close enough streams to shrink the window without causing a MAX
renjietang22305852020-04-06 15:05:18 -0700424 // STREAMS to be generated. The loop
QUICHE teama6ef0a62019-03-07 20:34:33 -0500425 // will make that many stream IDs available, so the last CloseStream should
fkastenholz3c4eabf2019-04-22 07:49:59 -0700426 // cause a MAX STREAMS frame to be generated.
renjietang22305852020-04-06 15:05:18 -0700427 int i =
428 static_cast<int>(stream_id_manager_.incoming_initial_max_open_streams() /
renjietang53570412020-04-07 06:32:17 -0700429 GetQuicFlag(FLAGS_quic_max_streams_window_divisor));
fkastenholz3c4eabf2019-04-22 07:49:59 -0700430 QuicStreamId id =
rcha8b56e42019-09-20 10:41:48 -0700431 QuicStreamIdManagerPeer::GetFirstIncomingStreamId(&stream_id_manager_);
renjietang22305852020-04-06 15:05:18 -0700432 EXPECT_CALL(delegate_, SendMaxStreams(first_advert + i, IsUnidirectional()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500433 while (i) {
renjietang7133ea92020-04-01 12:49:36 -0700434 EXPECT_TRUE(
435 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(id, nullptr));
rcha8b56e42019-09-20 10:41:48 -0700436 stream_id_manager_.OnStreamClosed(id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500437 i--;
renjietang01e6f382020-04-02 13:36:14 -0700438 id += QuicUtils::StreamIdDelta(transport_version());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500439 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500440}
441
rch9301d3c2019-09-20 14:30:48 -0700442TEST_P(QuicStreamIdManagerTest, NewStreamDoesNotExceedLimit) {
renjietangab9039a2020-03-30 14:53:19 -0700443 EXPECT_TRUE(stream_id_manager_.MaybeAllowNewOutgoingStreams(100));
fkastenholz56055be2019-09-17 11:17:37 -0700444
rcha8b56e42019-09-20 10:41:48 -0700445 size_t stream_count = stream_id_manager_.outgoing_max_streams();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500446 EXPECT_NE(0u, stream_count);
rcha8b56e42019-09-20 10:41:48 -0700447
QUICHE teama6ef0a62019-03-07 20:34:33 -0500448 while (stream_count) {
rcha8b56e42019-09-20 10:41:48 -0700449 EXPECT_TRUE(stream_id_manager_.CanOpenNextOutgoingStream());
450 stream_id_manager_.GetNextOutgoingStreamId();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500451 stream_count--;
452 }
fkastenholz3c4eabf2019-04-22 07:49:59 -0700453
rcha8b56e42019-09-20 10:41:48 -0700454 EXPECT_EQ(stream_id_manager_.outgoing_stream_count(),
455 stream_id_manager_.outgoing_max_streams());
fayang769172b2020-03-19 14:27:39 -0700456 // Create another, it should fail.
rcha8b56e42019-09-20 10:41:48 -0700457 EXPECT_FALSE(stream_id_manager_.CanOpenNextOutgoingStream());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500458}
459
rch9301d3c2019-09-20 14:30:48 -0700460TEST_P(QuicStreamIdManagerTest, AvailableStreams) {
renjietang7133ea92020-04-01 12:49:36 -0700461 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(GetNthIncomingStreamId(3),
462 nullptr);
rch9301d3c2019-09-20 14:30:48 -0700463
464 EXPECT_TRUE(stream_id_manager_.IsAvailableStream(GetNthIncomingStreamId(1)));
465 EXPECT_TRUE(stream_id_manager_.IsAvailableStream(GetNthIncomingStreamId(2)));
466 EXPECT_FALSE(stream_id_manager_.IsAvailableStream(GetNthIncomingStreamId(3)));
467 EXPECT_TRUE(stream_id_manager_.IsAvailableStream(GetNthIncomingStreamId(4)));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500468}
469
470// Tests that if MaybeIncreaseLargestPeerStreamId is given an extremely
471// large stream ID (larger than the limit) it is rejected.
472// This is a regression for Chromium bugs 909987 and 910040
rch9301d3c2019-09-20 14:30:48 -0700473TEST_P(QuicStreamIdManagerTest, ExtremeMaybeIncreaseLargestPeerStreamId) {
474 QuicStreamId too_big_stream_id = GetNthIncomingStreamId(
475 stream_id_manager_.incoming_actual_max_streams() + 20);
nharper46833c32019-05-15 21:33:05 -0700476
renjietang7133ea92020-04-01 12:49:36 -0700477 std::string error_details;
478 EXPECT_FALSE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(
479 too_big_stream_id, &error_details));
480 EXPECT_EQ(error_details,
481 quiche::QuicheStrCat("Stream id ", too_big_stream_id,
482 " would exceed stream count limit 100"));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500483}
484
QUICHE teama6ef0a62019-03-07 20:34:33 -0500485} // namespace
486} // namespace test
487} // namespace quic