blob: 17d76b23c925f586c80aa236b38055a82d7f375f [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:
rcha8b56e42019-09-20 10:41:48 -070027 MOCK_METHOD1(OnCanCreateNewOutgoingStream, void(bool unidirectional));
renjietangff4b2b62020-02-12 16:52:32 -080028 MOCK_METHOD2(OnStreamIdManagerError,
rcha8b56e42019-09-20 10:41:48 -070029 void(QuicErrorCode error_code, std::string error_details));
30 MOCK_METHOD2(SendMaxStreams,
31 void(QuicStreamCount stream_count, bool unidirectional));
QUICHE teama6ef0a62019-03-07 20:34:33 -050032};
33
rch9301d3c2019-09-20 14:30:48 -070034struct TestParams {
dschinazi38cc1ee2020-02-28 14:33:58 -080035 TestParams(ParsedQuicVersion version,
36 Perspective perspective,
37 bool is_unidirectional)
38 : version(version),
39 perspective(perspective),
40 is_unidirectional(is_unidirectional) {}
rch9301d3c2019-09-20 14:30:48 -070041
dschinazi38cc1ee2020-02-28 14:33:58 -080042 ParsedQuicVersion version;
rch9301d3c2019-09-20 14:30:48 -070043 Perspective perspective;
44 bool is_unidirectional;
45};
46
47// Used by ::testing::PrintToStringParamName().
48std::string PrintToString(const TestParams& p) {
dmcardlecf0bfcf2019-12-13 08:08:21 -080049 return quiche::QuicheStrCat(
dschinazi38cc1ee2020-02-28 14:33:58 -080050 ParsedQuicVersionToString(p.version), "_",
rch9301d3c2019-09-20 14:30:48 -070051 (p.perspective == Perspective::IS_CLIENT ? "Client" : "Server"),
52 (p.is_unidirectional ? "Unidirectional" : "Bidirectional"));
53}
54
55std::vector<TestParams> GetTestParams() {
56 std::vector<TestParams> params;
dschinazi38cc1ee2020-02-28 14:33:58 -080057 for (const ParsedQuicVersion& version : AllSupportedVersions()) {
58 if (!version.HasIetfQuicFrames()) {
59 continue;
60 }
61 for (Perspective perspective :
62 {Perspective::IS_CLIENT, Perspective::IS_SERVER}) {
63 for (bool is_unidirectional : {true, false}) {
64 params.push_back(TestParams(version, perspective, is_unidirectional));
65 }
rch9301d3c2019-09-20 14:30:48 -070066 }
67 }
68 return params;
69}
70
71class QuicStreamIdManagerTest : public QuicTestWithParam<TestParams> {
QUICHE teama6ef0a62019-03-07 20:34:33 -050072 protected:
rch9301d3c2019-09-20 14:30:48 -070073 QuicStreamIdManagerTest()
rcha8b56e42019-09-20 10:41:48 -070074 : stream_id_manager_(&delegate_,
rch9301d3c2019-09-20 14:30:48 -070075 IsUnidirectional(),
76 perspective(),
77 transport_version(),
renjietang315428e2020-01-27 10:18:12 -080078 0,
rch9301d3c2019-09-20 14:30:48 -070079 kDefaultMaxStreamsPerConnection) {
80 DCHECK(VersionHasIetfQuicFrames(transport_version()));
81 }
QUICHE teama6ef0a62019-03-07 20:34:33 -050082
dschinazi38cc1ee2020-02-28 14:33:58 -080083 QuicTransportVersion transport_version() const {
84 return GetParam().version.transport_version;
85 }
QUICHE teama6ef0a62019-03-07 20:34:33 -050086
rch9301d3c2019-09-20 14:30:48 -070087 // Returns the stream ID for the Nth incoming stream (created by the peer)
88 // of the corresponding directionality of this manager.
89 QuicStreamId GetNthIncomingStreamId(int n) {
90 return kV99StreamIdIncrement * n +
91 (IsUnidirectional()
92 ? QuicUtils::GetFirstUnidirectionalStreamId(
93 transport_version(),
94 QuicUtils::InvertPerspective(perspective()))
95 : QuicUtils::GetFirstBidirectionalStreamId(
96 transport_version(),
97 QuicUtils::InvertPerspective(perspective())));
QUICHE teama6ef0a62019-03-07 20:34:33 -050098 }
99
rch9301d3c2019-09-20 14:30:48 -0700100 bool IsUnidirectional() { return GetParam().is_unidirectional; }
101 Perspective perspective() { return GetParam().perspective; }
fkastenholz3c4eabf2019-04-22 07:49:59 -0700102
rcha8b56e42019-09-20 10:41:48 -0700103 StrictMock<MockDelegate> delegate_;
104 QuicStreamIdManager stream_id_manager_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500105};
106
dschinazi142051a2019-09-18 18:17:29 -0700107INSTANTIATE_TEST_SUITE_P(Tests,
rch9301d3c2019-09-20 14:30:48 -0700108 QuicStreamIdManagerTest,
109 ::testing::ValuesIn(GetTestParams()),
dschinazi142051a2019-09-18 18:17:29 -0700110 ::testing::PrintToStringParamName());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500111
rch9301d3c2019-09-20 14:30:48 -0700112TEST_P(QuicStreamIdManagerTest, Initialization) {
renjietang315428e2020-01-27 10:18:12 -0800113 EXPECT_EQ(0u, stream_id_manager_.outgoing_max_streams());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700114
QUICHE teama6ef0a62019-03-07 20:34:33 -0500115 EXPECT_EQ(kDefaultMaxStreamsPerConnection,
rcha8b56e42019-09-20 10:41:48 -0700116 stream_id_manager_.incoming_actual_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500117 EXPECT_EQ(kDefaultMaxStreamsPerConnection,
rcha8b56e42019-09-20 10:41:48 -0700118 stream_id_manager_.incoming_advertised_max_streams());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700119 EXPECT_EQ(kDefaultMaxStreamsPerConnection,
rcha8b56e42019-09-20 10:41:48 -0700120 stream_id_manager_.incoming_initial_max_open_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500121
122 // The window for advertising updates to the MAX STREAM ID is half the number
123 // of streams allowed.
rch9301d3c2019-09-20 14:30:48 -0700124 EXPECT_EQ(kDefaultMaxStreamsPerConnection / 2,
rcha8b56e42019-09-20 10:41:48 -0700125 stream_id_manager_.max_streams_window());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500126}
127
128// This test checks that the stream advertisement window is set to 1
129// if the number of stream ids is 1. This is a special case in the code.
rch9301d3c2019-09-20 14:30:48 -0700130TEST_P(QuicStreamIdManagerTest, CheckMaxStreamsWindowForSingleStream) {
rcha8b56e42019-09-20 10:41:48 -0700131 stream_id_manager_.SetMaxOpenIncomingStreams(1);
132 EXPECT_EQ(1u, stream_id_manager_.incoming_initial_max_open_streams());
133 EXPECT_EQ(1u, stream_id_manager_.incoming_actual_max_streams());
rcha8b56e42019-09-20 10:41:48 -0700134 EXPECT_EQ(1u, stream_id_manager_.max_streams_window());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500135}
136
rch9301d3c2019-09-20 14:30:48 -0700137TEST_P(QuicStreamIdManagerTest, CheckMaxStreamsBadValuesOverMaxFailsOutgoing) {
renjietangb885a122020-03-20 08:24:16 -0700138 QuicStreamCount implementation_max = QuicUtils::GetMaxStreamCount();
fkastenholz3c4eabf2019-04-22 07:49:59 -0700139 // Ensure that the limit is less than the implementation maximum.
rcha8b56e42019-09-20 10:41:48 -0700140 EXPECT_LT(stream_id_manager_.outgoing_max_streams(), implementation_max);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700141
rch9301d3c2019-09-20 14:30:48 -0700142 EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700143 stream_id_manager_.SetMaxOpenOutgoingStreams(implementation_max + 1);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700144 // Should be pegged at the max.
rcha8b56e42019-09-20 10:41:48 -0700145 EXPECT_EQ(implementation_max, stream_id_manager_.outgoing_max_streams());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700146}
147
fkastenholz3c4eabf2019-04-22 07:49:59 -0700148// Check the case of the stream count in a STREAMS_BLOCKED frame is less than
149// the count most recently advertised in a MAX_STREAMS frame. This should cause
150// a MAX_STREAMS frame with the most recently advertised count to be sent.
rch9301d3c2019-09-20 14:30:48 -0700151TEST_P(QuicStreamIdManagerTest, ProcessStreamsBlockedOk) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700152 QuicStreamCount stream_count =
rcha8b56e42019-09-20 10:41:48 -0700153 stream_id_manager_.incoming_initial_max_open_streams();
rch9301d3c2019-09-20 14:30:48 -0700154 QuicStreamsBlockedFrame frame(0, stream_count - 1, IsUnidirectional());
155 EXPECT_CALL(delegate_, SendMaxStreams(stream_count, IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700156 stream_id_manager_.OnStreamsBlockedFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500157}
158
fkastenholz3c4eabf2019-04-22 07:49:59 -0700159// Check the case of the stream count in a STREAMS_BLOCKED frame is equal to the
160// count most recently advertised in a MAX_STREAMS frame. No MAX_STREAMS
161// should be generated.
rch9301d3c2019-09-20 14:30:48 -0700162TEST_P(QuicStreamIdManagerTest, ProcessStreamsBlockedNoOp) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700163 QuicStreamCount stream_count =
rcha8b56e42019-09-20 10:41:48 -0700164 stream_id_manager_.incoming_initial_max_open_streams();
rch9301d3c2019-09-20 14:30:48 -0700165 QuicStreamsBlockedFrame frame(0, stream_count, IsUnidirectional());
rcha8b56e42019-09-20 10:41:48 -0700166 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500167}
168
fkastenholz3c4eabf2019-04-22 07:49:59 -0700169// Check the case of the stream count in a STREAMS_BLOCKED frame is greater than
170// the count most recently advertised in a MAX_STREAMS frame. Expect a
QUICHE teama6ef0a62019-03-07 20:34:33 -0500171// connection close with an error.
rch9301d3c2019-09-20 14:30:48 -0700172TEST_P(QuicStreamIdManagerTest, ProcessStreamsBlockedTooBig) {
renjietangff4b2b62020-02-12 16:52:32 -0800173 EXPECT_CALL(delegate_, OnStreamIdManagerError(QUIC_STREAMS_BLOCKED_ERROR, _));
rcha8b56e42019-09-20 10:41:48 -0700174 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700175 QuicStreamCount stream_count =
rcha8b56e42019-09-20 10:41:48 -0700176 stream_id_manager_.incoming_initial_max_open_streams() + 1;
rch9301d3c2019-09-20 14:30:48 -0700177 QuicStreamsBlockedFrame frame(0, stream_count, IsUnidirectional());
rcha8b56e42019-09-20 10:41:48 -0700178 stream_id_manager_.OnStreamsBlockedFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500179}
180
181// Same basic tests as above, but calls
182// QuicStreamIdManager::MaybeIncreaseLargestPeerStreamId directly, avoiding the
183// call chain. The intent is that if there is a problem, the following tests
184// will point to either the stream ID manager or the call chain. They also
185// provide specific, small scale, tests of a public QuicStreamIdManager method.
186// First test make sure that streams with ids below the limit are accepted.
rch9301d3c2019-09-20 14:30:48 -0700187TEST_P(QuicStreamIdManagerTest, IsIncomingStreamIdValidBelowLimit) {
188 QuicStreamId stream_id = GetNthIncomingStreamId(
189 stream_id_manager_.incoming_actual_max_streams() - 2);
renjietangff4b2b62020-02-12 16:52:32 -0800190 EXPECT_CALL(delegate_, OnStreamIdManagerError(_, _)).Times(0);
rcha8b56e42019-09-20 10:41:48 -0700191 EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500192}
193
194// Accept a stream with an ID that equals the limit.
rch9301d3c2019-09-20 14:30:48 -0700195TEST_P(QuicStreamIdManagerTest, IsIncomingStreamIdValidAtLimit) {
196 QuicStreamId stream_id = GetNthIncomingStreamId(
197 stream_id_manager_.incoming_actual_max_streams() - 1);
renjietangff4b2b62020-02-12 16:52:32 -0800198 EXPECT_CALL(delegate_, OnStreamIdManagerError(_, _)).Times(0);
rcha8b56e42019-09-20 10:41:48 -0700199 EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500200}
201
202// Close the connection if the id exceeds the limit.
rch9301d3c2019-09-20 14:30:48 -0700203TEST_P(QuicStreamIdManagerTest, IsIncomingStreamIdInValidAboveLimit) {
204 QuicStreamId stream_id =
205 GetNthIncomingStreamId(stream_id_manager_.incoming_actual_max_streams());
dmcardlecf0bfcf2019-12-13 08:08:21 -0800206 std::string error_details = quiche::QuicheStrCat(
rch9301d3c2019-09-20 14:30:48 -0700207 "Stream id ", stream_id, " would exceed stream count limit 100");
renjietangff4b2b62020-02-12 16:52:32 -0800208 EXPECT_CALL(delegate_,
209 OnStreamIdManagerError(QUIC_INVALID_STREAM_ID, error_details));
rcha8b56e42019-09-20 10:41:48 -0700210 EXPECT_FALSE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500211}
212
rch9301d3c2019-09-20 14:30:48 -0700213TEST_P(QuicStreamIdManagerTest, OnMaxStreamsFrame) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700214 QuicMaxStreamsFrame frame;
renjietang315428e2020-01-27 10:18:12 -0800215 frame.stream_count = 10;
fkastenholz3c4eabf2019-04-22 07:49:59 -0700216
rch9301d3c2019-09-20 14:30:48 -0700217 frame.unidirectional = IsUnidirectional();
218 EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700219 EXPECT_TRUE(stream_id_manager_.OnMaxStreamsFrame(frame));
renjietang315428e2020-01-27 10:18:12 -0800220 EXPECT_EQ(10u, stream_id_manager_.outgoing_max_streams());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700221
222 QuicStreamCount save_outgoing_max_streams =
rcha8b56e42019-09-20 10:41:48 -0700223 stream_id_manager_.outgoing_max_streams();
fkastenholz3c4eabf2019-04-22 07:49:59 -0700224 // Now that there has been one MAX STREAMS frame, we should not
225 // accept a MAX_STREAMS that reduces the limit...
renjietang315428e2020-01-27 10:18:12 -0800226 frame.stream_count = 8;
rch9301d3c2019-09-20 14:30:48 -0700227 frame.unidirectional = IsUnidirectional();
rcha8b56e42019-09-20 10:41:48 -0700228 EXPECT_TRUE(stream_id_manager_.OnMaxStreamsFrame(frame));
fkastenholz3c4eabf2019-04-22 07:49:59 -0700229 // should not change from previous setting.
230 EXPECT_EQ(save_outgoing_max_streams,
rcha8b56e42019-09-20 10:41:48 -0700231 stream_id_manager_.outgoing_max_streams());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700232
233 // A stream count greater than the current limit should increase the limit.
renjietang315428e2020-01-27 10:18:12 -0800234 frame.stream_count = 12;
rch9301d3c2019-09-20 14:30:48 -0700235 EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700236 EXPECT_TRUE(stream_id_manager_.OnMaxStreamsFrame(frame));
fkastenholz3c4eabf2019-04-22 07:49:59 -0700237
renjietang315428e2020-01-27 10:18:12 -0800238 EXPECT_EQ(12u, stream_id_manager_.outgoing_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500239}
240
rch9301d3c2019-09-20 14:30:48 -0700241TEST_P(QuicStreamIdManagerTest, OnStreamsBlockedFrame) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700242 // Get the current maximum allowed incoming stream count.
243 QuicStreamCount advertised_stream_count =
rcha8b56e42019-09-20 10:41:48 -0700244 stream_id_manager_.incoming_advertised_max_streams();
245
fkastenholz3c4eabf2019-04-22 07:49:59 -0700246 QuicStreamsBlockedFrame frame;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500247
rch9301d3c2019-09-20 14:30:48 -0700248 frame.unidirectional = IsUnidirectional();
fkastenholz3c4eabf2019-04-22 07:49:59 -0700249
250 // If the peer is saying it's blocked on the stream count that
QUICHE teama6ef0a62019-03-07 20:34:33 -0500251 // we've advertised, it's a noop since the peer has the correct information.
fkastenholz3c4eabf2019-04-22 07:49:59 -0700252 frame.stream_count = advertised_stream_count;
rcha8b56e42019-09-20 10:41:48 -0700253 EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500254
fkastenholz3c4eabf2019-04-22 07:49:59 -0700255 // If the peer is saying it's blocked on a stream count that is larger
QUICHE teama6ef0a62019-03-07 20:34:33 -0500256 // than what we've advertised, the connection should get closed.
fkastenholz3c4eabf2019-04-22 07:49:59 -0700257 frame.stream_count = advertised_stream_count + 1;
renjietangff4b2b62020-02-12 16:52:32 -0800258 EXPECT_CALL(delegate_, OnStreamIdManagerError(QUIC_STREAMS_BLOCKED_ERROR, _));
rcha8b56e42019-09-20 10:41:48 -0700259 EXPECT_FALSE(stream_id_manager_.OnStreamsBlockedFrame(frame));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500260
fkastenholz3c4eabf2019-04-22 07:49:59 -0700261 // If the peer is saying it's blocked on a count that is less than
262 // our actual count, we send a MAX_STREAMS frame and update
QUICHE teama6ef0a62019-03-07 20:34:33 -0500263 // the advertised value.
264 // First, need to bump up the actual max so there is room for the MAX
fkastenholz3c4eabf2019-04-22 07:49:59 -0700265 // STREAMS frame to send a larger ID.
266 QuicStreamCount actual_stream_count =
rcha8b56e42019-09-20 10:41:48 -0700267 stream_id_manager_.incoming_actual_max_streams();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500268
fkastenholz3c4eabf2019-04-22 07:49:59 -0700269 // Closing a stream will result in the ability to initiate one more
270 // stream
rcha8b56e42019-09-20 10:41:48 -0700271 stream_id_manager_.OnStreamClosed(
272 QuicStreamIdManagerPeer::GetFirstIncomingStreamId(&stream_id_manager_));
fkastenholzd035fc32019-04-23 12:24:02 -0700273 EXPECT_EQ(actual_stream_count + 1u,
rcha8b56e42019-09-20 10:41:48 -0700274 stream_id_manager_.incoming_actual_max_streams());
275 EXPECT_EQ(stream_id_manager_.incoming_actual_max_streams(),
276 stream_id_manager_.incoming_advertised_max_streams() + 1u);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700277
278 // Now simulate receiving a STREAMS_BLOCKED frame...
279 // Changing the actual maximum, above, forces a MAX_STREAMS frame to be
280 // sent, so the logic for that (SendMaxStreamsFrame(), etc) is tested.
281
282 // The STREAMS_BLOCKED frame contains the previous advertised count,
283 // not the one that the peer would have received as a result of the
284 // MAX_STREAMS sent earler.
285 frame.stream_count = advertised_stream_count;
286
rcha8b56e42019-09-20 10:41:48 -0700287 EXPECT_CALL(delegate_,
288 SendMaxStreams(stream_id_manager_.incoming_actual_max_streams(),
rch9301d3c2019-09-20 14:30:48 -0700289 IsUnidirectional()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500290
rcha8b56e42019-09-20 10:41:48 -0700291 EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame));
fkastenholz3c4eabf2019-04-22 07:49:59 -0700292 // Check that the saved frame is correct.
rcha8b56e42019-09-20 10:41:48 -0700293 EXPECT_EQ(stream_id_manager_.incoming_actual_max_streams(),
294 stream_id_manager_.incoming_advertised_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500295}
296
rch9301d3c2019-09-20 14:30:48 -0700297TEST_P(QuicStreamIdManagerTest, GetNextOutgoingStream) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500298 // Number of streams we can open and the first one we should get when
299 // opening...
renjietang7fc869e2019-08-14 11:02:42 -0700300 size_t number_of_streams = kDefaultMaxStreamsPerConnection;
fkastenholz56055be2019-09-17 11:17:37 -0700301
rch9301d3c2019-09-20 14:30:48 -0700302 EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidirectional()));
renjietang315428e2020-01-27 10:18:12 -0800303 stream_id_manager_.SetMaxOpenOutgoingStreams(kDefaultMaxStreamsPerConnection);
rcha8b56e42019-09-20 10:41:48 -0700304
QUICHE teama6ef0a62019-03-07 20:34:33 -0500305 QuicStreamId stream_id =
rch9301d3c2019-09-20 14:30:48 -0700306 IsUnidirectional()
307 ? QuicUtils::GetFirstUnidirectionalStreamId(
308 transport_version(), stream_id_manager_.perspective())
309 : QuicUtils::GetFirstBidirectionalStreamId(
310 transport_version(), stream_id_manager_.perspective());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500311
rcha8b56e42019-09-20 10:41:48 -0700312 EXPECT_EQ(number_of_streams, stream_id_manager_.outgoing_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500313 while (number_of_streams) {
rcha8b56e42019-09-20 10:41:48 -0700314 EXPECT_TRUE(stream_id_manager_.CanOpenNextOutgoingStream());
315 EXPECT_EQ(stream_id, stream_id_manager_.GetNextOutgoingStreamId());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500316 stream_id += kV99StreamIdIncrement;
317 number_of_streams--;
318 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500319
320 // If we try to check that the next outgoing stream id is available it should
fayang769172b2020-03-19 14:27:39 -0700321 // fail.
rcha8b56e42019-09-20 10:41:48 -0700322 EXPECT_FALSE(stream_id_manager_.CanOpenNextOutgoingStream());
323
QUICHE teama6ef0a62019-03-07 20:34:33 -0500324 // If we try to get the next id (above the limit), it should cause a quic-bug.
325 EXPECT_QUIC_BUG(
rcha8b56e42019-09-20 10:41:48 -0700326 stream_id_manager_.GetNextOutgoingStreamId(),
fkastenholz3c4eabf2019-04-22 07:49:59 -0700327 "Attempt to allocate a new outgoing stream that would exceed the limit");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500328}
329
rch9301d3c2019-09-20 14:30:48 -0700330TEST_P(QuicStreamIdManagerTest, MaybeIncreaseLargestPeerStreamId) {
331 QuicStreamId max_stream_id = GetNthIncomingStreamId(
332 stream_id_manager_.incoming_actual_max_streams() - 1);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700333 EXPECT_TRUE(
rcha8b56e42019-09-20 10:41:48 -0700334 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(max_stream_id));
fkastenholz3c4eabf2019-04-22 07:49:59 -0700335
rch9301d3c2019-09-20 14:30:48 -0700336 QuicStreamId first_stream_id = GetNthIncomingStreamId(0);
337 EXPECT_TRUE(
338 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(first_stream_id));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500339 // A bad stream ID results in a closed connection.
renjietangff4b2b62020-02-12 16:52:32 -0800340 EXPECT_CALL(delegate_, OnStreamIdManagerError(QUIC_INVALID_STREAM_ID, _));
rcha8b56e42019-09-20 10:41:48 -0700341 EXPECT_FALSE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(
fkastenholz3c4eabf2019-04-22 07:49:59 -0700342 max_stream_id + kV99StreamIdIncrement));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500343}
344
rch9301d3c2019-09-20 14:30:48 -0700345TEST_P(QuicStreamIdManagerTest, MaxStreamsWindow) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700346 // Test that a MAX_STREAMS frame is generated when the peer has less than
347 // |max_streams_window_| streams left that it can initiate.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500348
fkastenholz3c4eabf2019-04-22 07:49:59 -0700349 // First, open, and then close, max_streams_window_ streams. This will
350 // max_streams_window_ streams available for the peer -- no MAX_STREAMS
QUICHE teama6ef0a62019-03-07 20:34:33 -0500351 // should be sent. The -1 is because the check in
fkastenholz3c4eabf2019-04-22 07:49:59 -0700352 // QuicStreamIdManager::MaybeSendMaxStreamsFrame sends a MAX_STREAMS if the
353 // number of available streams at the peer is <= |max_streams_window_|
rcha8b56e42019-09-20 10:41:48 -0700354 int stream_count = stream_id_manager_.max_streams_window() - 1;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500355
356 // Should not get a control-frame transmission since the peer should have
357 // "plenty" of stream IDs to use.
rcha8b56e42019-09-20 10:41:48 -0700358 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700359
360 // Get the first incoming stream ID to try and allocate.
rch9301d3c2019-09-20 14:30:48 -0700361 QuicStreamId stream_id = GetNthIncomingStreamId(0);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500362 size_t old_available_incoming_streams =
rcha8b56e42019-09-20 10:41:48 -0700363 stream_id_manager_.available_incoming_streams();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500364 while (stream_count) {
rcha8b56e42019-09-20 10:41:48 -0700365 EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500366
fkastenholz3c4eabf2019-04-22 07:49:59 -0700367 // This node should think that the peer believes it has one fewer
368 // stream it can create.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500369 old_available_incoming_streams--;
370 EXPECT_EQ(old_available_incoming_streams,
rcha8b56e42019-09-20 10:41:48 -0700371 stream_id_manager_.available_incoming_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500372
373 stream_count--;
374 stream_id += kV99StreamIdIncrement;
375 }
376
fkastenholz3c4eabf2019-04-22 07:49:59 -0700377 // Now close them, still should get no MAX_STREAMS
rcha8b56e42019-09-20 10:41:48 -0700378 stream_count = stream_id_manager_.max_streams_window();
rch9301d3c2019-09-20 14:30:48 -0700379 stream_id = GetNthIncomingStreamId(0);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700380 QuicStreamCount expected_actual_max =
rcha8b56e42019-09-20 10:41:48 -0700381 stream_id_manager_.incoming_actual_max_streams();
fkastenholz3c4eabf2019-04-22 07:49:59 -0700382 QuicStreamCount expected_advertised_max_streams =
rcha8b56e42019-09-20 10:41:48 -0700383 stream_id_manager_.incoming_advertised_max_streams();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500384 while (stream_count) {
rcha8b56e42019-09-20 10:41:48 -0700385 stream_id_manager_.OnStreamClosed(stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500386 stream_count--;
387 stream_id += kV99StreamIdIncrement;
fkastenholz3c4eabf2019-04-22 07:49:59 -0700388 expected_actual_max++;
389 EXPECT_EQ(expected_actual_max,
rcha8b56e42019-09-20 10:41:48 -0700390 stream_id_manager_.incoming_actual_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500391 // Advertised maximum should remain the same.
fkastenholz3c4eabf2019-04-22 07:49:59 -0700392 EXPECT_EQ(expected_advertised_max_streams,
rcha8b56e42019-09-20 10:41:48 -0700393 stream_id_manager_.incoming_advertised_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500394 }
395
396 // This should not change.
397 EXPECT_EQ(old_available_incoming_streams,
rcha8b56e42019-09-20 10:41:48 -0700398 stream_id_manager_.available_incoming_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500399
fkastenholz3c4eabf2019-04-22 07:49:59 -0700400 // Now whenever we close a stream we should get a MAX_STREAMS frame.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500401 // Above code closed all the open streams, so we have to open/close
rcha8b56e42019-09-20 10:41:48 -0700402 // EXPECT_CALL(delegate_,
403 // SendMaxStreams(stream_id_manager_.incoming_actual_max_streams(),
rch9301d3c2019-09-20 14:30:48 -0700404 // IsUnidirectional()));
405 EXPECT_CALL(delegate_, SendMaxStreams(_, IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700406 EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id));
407 stream_id_manager_.OnStreamClosed(stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500408}
409
rch9301d3c2019-09-20 14:30:48 -0700410TEST_P(QuicStreamIdManagerTest, StreamsBlockedEdgeConditions) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700411 QuicStreamsBlockedFrame frame;
rch9301d3c2019-09-20 14:30:48 -0700412 frame.unidirectional = IsUnidirectional();
fkastenholz3c4eabf2019-04-22 07:49:59 -0700413
414 // Check that receipt of a STREAMS BLOCKED with stream-count = 0 does nothing
415 // when max_allowed_incoming_streams is 0.
rcha8b56e42019-09-20 10:41:48 -0700416 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
rcha8b56e42019-09-20 10:41:48 -0700417 stream_id_manager_.SetMaxOpenIncomingStreams(0);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700418 frame.stream_count = 0;
rcha8b56e42019-09-20 10:41:48 -0700419 stream_id_manager_.OnStreamsBlockedFrame(frame);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700420
421 // Check that receipt of a STREAMS BLOCKED with stream-count = 0 invokes a
422 // MAX STREAMS, count = 123, when the MaxOpen... is set to 123.
rch9301d3c2019-09-20 14:30:48 -0700423 EXPECT_CALL(delegate_, SendMaxStreams(123u, IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700424 stream_id_manager_.SetMaxOpenIncomingStreams(123);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700425 frame.stream_count = 0;
rcha8b56e42019-09-20 10:41:48 -0700426 stream_id_manager_.OnStreamsBlockedFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500427}
428
rch9301d3c2019-09-20 14:30:48 -0700429TEST_P(QuicStreamIdManagerTest, CheckMaxAllowedOutgoingInitialization) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500430 const size_t kIncomingStreamCount = 123;
rch9301d3c2019-09-20 14:30:48 -0700431 EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700432 stream_id_manager_.SetMaxOpenOutgoingStreams(kIncomingStreamCount);
433 EXPECT_EQ(kIncomingStreamCount, stream_id_manager_.outgoing_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500434}
435
fkastenholz3c4eabf2019-04-22 07:49:59 -0700436// Test that a MAX_STREAMS frame is generated when half the stream ids become
QUICHE teama6ef0a62019-03-07 20:34:33 -0500437// available. This has a useful side effect of testing that when streams are
438// closed, the number of available stream ids increases.
rch9301d3c2019-09-20 14:30:48 -0700439TEST_P(QuicStreamIdManagerTest, MaxStreamsSlidingWindow) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700440 QuicStreamCount first_advert =
rcha8b56e42019-09-20 10:41:48 -0700441 stream_id_manager_.incoming_advertised_max_streams();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500442
fkastenholz3c4eabf2019-04-22 07:49:59 -0700443 // Open/close enough streams to shrink the window without causing a MAX
444 // STREAMS to be generated. The window will open (and a MAX STREAMS generated)
445 // when max_streams_window() stream IDs have been made available. The loop
QUICHE teama6ef0a62019-03-07 20:34:33 -0500446 // will make that many stream IDs available, so the last CloseStream should
rcha8b56e42019-09-20 10:41:48 -0700447
fkastenholz3c4eabf2019-04-22 07:49:59 -0700448 // cause a MAX STREAMS frame to be generated.
rcha8b56e42019-09-20 10:41:48 -0700449 int i = static_cast<int>(stream_id_manager_.max_streams_window());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700450 QuicStreamId id =
rcha8b56e42019-09-20 10:41:48 -0700451 QuicStreamIdManagerPeer::GetFirstIncomingStreamId(&stream_id_manager_);
452 EXPECT_CALL(
453 delegate_,
454 SendMaxStreams(first_advert + stream_id_manager_.max_streams_window(),
rch9301d3c2019-09-20 14:30:48 -0700455 IsUnidirectional()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500456 while (i) {
rcha8b56e42019-09-20 10:41:48 -0700457 EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(id));
458 stream_id_manager_.OnStreamClosed(id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500459 i--;
460 id += kV99StreamIdIncrement;
461 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500462}
463
rch9301d3c2019-09-20 14:30:48 -0700464TEST_P(QuicStreamIdManagerTest, NewStreamDoesNotExceedLimit) {
465 EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700466 stream_id_manager_.SetMaxOpenOutgoingStreams(100);
fkastenholz56055be2019-09-17 11:17:37 -0700467
rcha8b56e42019-09-20 10:41:48 -0700468 size_t stream_count = stream_id_manager_.outgoing_max_streams();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500469 EXPECT_NE(0u, stream_count);
rcha8b56e42019-09-20 10:41:48 -0700470
QUICHE teama6ef0a62019-03-07 20:34:33 -0500471 while (stream_count) {
rcha8b56e42019-09-20 10:41:48 -0700472 EXPECT_TRUE(stream_id_manager_.CanOpenNextOutgoingStream());
473 stream_id_manager_.GetNextOutgoingStreamId();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500474 stream_count--;
475 }
fkastenholz3c4eabf2019-04-22 07:49:59 -0700476
rcha8b56e42019-09-20 10:41:48 -0700477 EXPECT_EQ(stream_id_manager_.outgoing_stream_count(),
478 stream_id_manager_.outgoing_max_streams());
fayang769172b2020-03-19 14:27:39 -0700479 // Create another, it should fail.
rcha8b56e42019-09-20 10:41:48 -0700480 EXPECT_FALSE(stream_id_manager_.CanOpenNextOutgoingStream());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500481}
482
rch9301d3c2019-09-20 14:30:48 -0700483TEST_P(QuicStreamIdManagerTest, AvailableStreams) {
rcha8b56e42019-09-20 10:41:48 -0700484 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(
rch9301d3c2019-09-20 14:30:48 -0700485 GetNthIncomingStreamId(3));
486
487 EXPECT_TRUE(stream_id_manager_.IsAvailableStream(GetNthIncomingStreamId(1)));
488 EXPECT_TRUE(stream_id_manager_.IsAvailableStream(GetNthIncomingStreamId(2)));
489 EXPECT_FALSE(stream_id_manager_.IsAvailableStream(GetNthIncomingStreamId(3)));
490 EXPECT_TRUE(stream_id_manager_.IsAvailableStream(GetNthIncomingStreamId(4)));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500491}
492
493// Tests that if MaybeIncreaseLargestPeerStreamId is given an extremely
494// large stream ID (larger than the limit) it is rejected.
495// This is a regression for Chromium bugs 909987 and 910040
rch9301d3c2019-09-20 14:30:48 -0700496TEST_P(QuicStreamIdManagerTest, ExtremeMaybeIncreaseLargestPeerStreamId) {
497 QuicStreamId too_big_stream_id = GetNthIncomingStreamId(
498 stream_id_manager_.incoming_actual_max_streams() + 20);
dmcardlecf0bfcf2019-12-13 08:08:21 -0800499 std::string error_details = quiche::QuicheStrCat(
rch9301d3c2019-09-20 14:30:48 -0700500 "Stream id ", too_big_stream_id, " would exceed stream count limit 100");
nharper46833c32019-05-15 21:33:05 -0700501
renjietangff4b2b62020-02-12 16:52:32 -0800502 EXPECT_CALL(delegate_,
503 OnStreamIdManagerError(QUIC_INVALID_STREAM_ID, error_details));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500504 EXPECT_FALSE(
rcha8b56e42019-09-20 10:41:48 -0700505 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(too_big_stream_id));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500506}
507
QUICHE teama6ef0a62019-03-07 20:34:33 -0500508} // namespace
509} // namespace test
510} // namespace quic