blob: a1142959422778cc73aa1762b1fdd9bc9f641fe2 [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));
32 MOCK_METHOD2(SendStreamsBlocked,
33 void(QuicStreamCount stream_count, bool unidirectional));
QUICHE teama6ef0a62019-03-07 20:34:33 -050034};
35
rch9301d3c2019-09-20 14:30:48 -070036struct TestParams {
dschinazi38cc1ee2020-02-28 14:33:58 -080037 TestParams(ParsedQuicVersion version,
38 Perspective perspective,
39 bool is_unidirectional)
40 : version(version),
41 perspective(perspective),
42 is_unidirectional(is_unidirectional) {}
rch9301d3c2019-09-20 14:30:48 -070043
dschinazi38cc1ee2020-02-28 14:33:58 -080044 ParsedQuicVersion version;
rch9301d3c2019-09-20 14:30:48 -070045 Perspective perspective;
46 bool is_unidirectional;
47};
48
49// Used by ::testing::PrintToStringParamName().
50std::string PrintToString(const TestParams& p) {
dmcardlecf0bfcf2019-12-13 08:08:21 -080051 return quiche::QuicheStrCat(
dschinazi38cc1ee2020-02-28 14:33:58 -080052 ParsedQuicVersionToString(p.version), "_",
rch9301d3c2019-09-20 14:30:48 -070053 (p.perspective == Perspective::IS_CLIENT ? "Client" : "Server"),
54 (p.is_unidirectional ? "Unidirectional" : "Bidirectional"));
55}
56
57std::vector<TestParams> GetTestParams() {
58 std::vector<TestParams> params;
dschinazi38cc1ee2020-02-28 14:33:58 -080059 for (const ParsedQuicVersion& version : AllSupportedVersions()) {
60 if (!version.HasIetfQuicFrames()) {
61 continue;
62 }
63 for (Perspective perspective :
64 {Perspective::IS_CLIENT, Perspective::IS_SERVER}) {
65 for (bool is_unidirectional : {true, false}) {
66 params.push_back(TestParams(version, perspective, is_unidirectional));
67 }
rch9301d3c2019-09-20 14:30:48 -070068 }
69 }
70 return params;
71}
72
73class QuicStreamIdManagerTest : public QuicTestWithParam<TestParams> {
QUICHE teama6ef0a62019-03-07 20:34:33 -050074 protected:
rch9301d3c2019-09-20 14:30:48 -070075 QuicStreamIdManagerTest()
rcha8b56e42019-09-20 10:41:48 -070076 : stream_id_manager_(&delegate_,
rch9301d3c2019-09-20 14:30:48 -070077 IsUnidirectional(),
78 perspective(),
79 transport_version(),
renjietang315428e2020-01-27 10:18:12 -080080 0,
rch9301d3c2019-09-20 14:30:48 -070081 kDefaultMaxStreamsPerConnection) {
82 DCHECK(VersionHasIetfQuicFrames(transport_version()));
83 }
QUICHE teama6ef0a62019-03-07 20:34:33 -050084
dschinazi38cc1ee2020-02-28 14:33:58 -080085 QuicTransportVersion transport_version() const {
86 return GetParam().version.transport_version;
87 }
QUICHE teama6ef0a62019-03-07 20:34:33 -050088
rch9301d3c2019-09-20 14:30:48 -070089 // Returns the stream ID for the Nth incoming stream (created by the peer)
90 // of the corresponding directionality of this manager.
91 QuicStreamId GetNthIncomingStreamId(int n) {
92 return kV99StreamIdIncrement * n +
93 (IsUnidirectional()
94 ? QuicUtils::GetFirstUnidirectionalStreamId(
95 transport_version(),
96 QuicUtils::InvertPerspective(perspective()))
97 : QuicUtils::GetFirstBidirectionalStreamId(
98 transport_version(),
99 QuicUtils::InvertPerspective(perspective())));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500100 }
101
rch9301d3c2019-09-20 14:30:48 -0700102 bool IsUnidirectional() { return GetParam().is_unidirectional; }
103 Perspective perspective() { return GetParam().perspective; }
fkastenholz3c4eabf2019-04-22 07:49:59 -0700104
rcha8b56e42019-09-20 10:41:48 -0700105 StrictMock<MockDelegate> delegate_;
106 QuicStreamIdManager stream_id_manager_;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500107};
108
dschinazi142051a2019-09-18 18:17:29 -0700109INSTANTIATE_TEST_SUITE_P(Tests,
rch9301d3c2019-09-20 14:30:48 -0700110 QuicStreamIdManagerTest,
111 ::testing::ValuesIn(GetTestParams()),
dschinazi142051a2019-09-18 18:17:29 -0700112 ::testing::PrintToStringParamName());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500113
rch9301d3c2019-09-20 14:30:48 -0700114TEST_P(QuicStreamIdManagerTest, Initialization) {
renjietang315428e2020-01-27 10:18:12 -0800115 EXPECT_EQ(0u, stream_id_manager_.outgoing_max_streams());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700116
QUICHE teama6ef0a62019-03-07 20:34:33 -0500117 EXPECT_EQ(kDefaultMaxStreamsPerConnection,
rcha8b56e42019-09-20 10:41:48 -0700118 stream_id_manager_.incoming_actual_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500119 EXPECT_EQ(kDefaultMaxStreamsPerConnection,
rcha8b56e42019-09-20 10:41:48 -0700120 stream_id_manager_.incoming_advertised_max_streams());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700121 EXPECT_EQ(kDefaultMaxStreamsPerConnection,
rcha8b56e42019-09-20 10:41:48 -0700122 stream_id_manager_.incoming_initial_max_open_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500123
124 // The window for advertising updates to the MAX STREAM ID is half the number
125 // of streams allowed.
rch9301d3c2019-09-20 14:30:48 -0700126 EXPECT_EQ(kDefaultMaxStreamsPerConnection / 2,
rcha8b56e42019-09-20 10:41:48 -0700127 stream_id_manager_.max_streams_window());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500128}
129
130// This test checks that the stream advertisement window is set to 1
131// if the number of stream ids is 1. This is a special case in the code.
rch9301d3c2019-09-20 14:30:48 -0700132TEST_P(QuicStreamIdManagerTest, CheckMaxStreamsWindowForSingleStream) {
rcha8b56e42019-09-20 10:41:48 -0700133 stream_id_manager_.SetMaxOpenIncomingStreams(1);
134 EXPECT_EQ(1u, stream_id_manager_.incoming_initial_max_open_streams());
135 EXPECT_EQ(1u, stream_id_manager_.incoming_actual_max_streams());
rcha8b56e42019-09-20 10:41:48 -0700136 EXPECT_EQ(1u, stream_id_manager_.max_streams_window());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500137}
138
rch9301d3c2019-09-20 14:30:48 -0700139TEST_P(QuicStreamIdManagerTest, CheckMaxStreamsBadValuesOverMaxFailsOutgoing) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700140 QuicStreamCount implementation_max =
rch9301d3c2019-09-20 14:30:48 -0700141 QuicUtils::GetMaxStreamCount(IsUnidirectional(), perspective());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700142 // Ensure that the limit is less than the implementation maximum.
rcha8b56e42019-09-20 10:41:48 -0700143 EXPECT_LT(stream_id_manager_.outgoing_max_streams(), implementation_max);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700144
rch9301d3c2019-09-20 14:30:48 -0700145 EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700146 stream_id_manager_.SetMaxOpenOutgoingStreams(implementation_max + 1);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700147 // Should be pegged at the max.
rcha8b56e42019-09-20 10:41:48 -0700148 EXPECT_EQ(implementation_max, stream_id_manager_.outgoing_max_streams());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700149}
150
151// Now do the same for the incoming streams
rch9301d3c2019-09-20 14:30:48 -0700152TEST_P(QuicStreamIdManagerTest, CheckMaxStreamsBadValuesIncoming) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700153 QuicStreamCount implementation_max =
rch9301d3c2019-09-20 14:30:48 -0700154 QuicUtils::GetMaxStreamCount(IsUnidirectional(), perspective());
rcha8b56e42019-09-20 10:41:48 -0700155 stream_id_manager_.SetMaxOpenIncomingStreams(implementation_max - 1u);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700156 EXPECT_EQ(implementation_max - 1u,
rcha8b56e42019-09-20 10:41:48 -0700157 stream_id_manager_.incoming_initial_max_open_streams());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700158 EXPECT_EQ(implementation_max - 1u,
rcha8b56e42019-09-20 10:41:48 -0700159 stream_id_manager_.incoming_actual_max_streams());
fkastenholzd035fc32019-04-23 12:24:02 -0700160 EXPECT_EQ((implementation_max - 1u) / 2u,
rcha8b56e42019-09-20 10:41:48 -0700161 stream_id_manager_.max_streams_window());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700162
rcha8b56e42019-09-20 10:41:48 -0700163 stream_id_manager_.SetMaxOpenIncomingStreams(implementation_max);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700164 EXPECT_EQ(implementation_max,
rcha8b56e42019-09-20 10:41:48 -0700165 stream_id_manager_.incoming_initial_max_open_streams());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700166 EXPECT_EQ(implementation_max,
rcha8b56e42019-09-20 10:41:48 -0700167 stream_id_manager_.incoming_actual_max_streams());
168 EXPECT_EQ(implementation_max / 2, stream_id_manager_.max_streams_window());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700169
170 // Reset to 1 so that we can detect the change.
rcha8b56e42019-09-20 10:41:48 -0700171 stream_id_manager_.SetMaxOpenIncomingStreams(1u);
172 EXPECT_EQ(1u, stream_id_manager_.incoming_initial_max_open_streams());
173 EXPECT_EQ(1u, stream_id_manager_.incoming_actual_max_streams());
174 EXPECT_EQ(1u, stream_id_manager_.max_streams_window());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700175 // Now try to exceed the max, without wrapping.
rcha8b56e42019-09-20 10:41:48 -0700176 stream_id_manager_.SetMaxOpenIncomingStreams(implementation_max + 1);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700177 EXPECT_EQ(implementation_max,
rcha8b56e42019-09-20 10:41:48 -0700178 stream_id_manager_.incoming_initial_max_open_streams());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700179 EXPECT_EQ(implementation_max,
rcha8b56e42019-09-20 10:41:48 -0700180 stream_id_manager_.incoming_actual_max_streams());
181 EXPECT_EQ(implementation_max / 2u, stream_id_manager_.max_streams_window());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700182}
183
184// Check the case of the stream count in a STREAMS_BLOCKED frame is less than
185// the count most recently advertised in a MAX_STREAMS frame. This should cause
186// a MAX_STREAMS frame with the most recently advertised count to be sent.
rch9301d3c2019-09-20 14:30:48 -0700187TEST_P(QuicStreamIdManagerTest, ProcessStreamsBlockedOk) {
rcha8b56e42019-09-20 10:41:48 -0700188 // Set the config negotiated so that the MAX_STREAMS is transmitted.
189 stream_id_manager_.OnConfigNegotiated();
190
fkastenholz3c4eabf2019-04-22 07:49:59 -0700191 QuicStreamCount stream_count =
rcha8b56e42019-09-20 10:41:48 -0700192 stream_id_manager_.incoming_initial_max_open_streams();
rch9301d3c2019-09-20 14:30:48 -0700193 QuicStreamsBlockedFrame frame(0, stream_count - 1, IsUnidirectional());
194 EXPECT_CALL(delegate_, SendMaxStreams(stream_count, IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700195 stream_id_manager_.OnStreamsBlockedFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500196}
197
fkastenholz3c4eabf2019-04-22 07:49:59 -0700198// Check the case of the stream count in a STREAMS_BLOCKED frame is equal to the
199// count most recently advertised in a MAX_STREAMS frame. No MAX_STREAMS
200// should be generated.
rch9301d3c2019-09-20 14:30:48 -0700201TEST_P(QuicStreamIdManagerTest, ProcessStreamsBlockedNoOp) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700202 QuicStreamCount stream_count =
rcha8b56e42019-09-20 10:41:48 -0700203 stream_id_manager_.incoming_initial_max_open_streams();
rch9301d3c2019-09-20 14:30:48 -0700204 QuicStreamsBlockedFrame frame(0, stream_count, IsUnidirectional());
rcha8b56e42019-09-20 10:41:48 -0700205 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500206}
207
fkastenholz3c4eabf2019-04-22 07:49:59 -0700208// Check the case of the stream count in a STREAMS_BLOCKED frame is greater than
209// the count most recently advertised in a MAX_STREAMS frame. Expect a
QUICHE teama6ef0a62019-03-07 20:34:33 -0500210// connection close with an error.
rch9301d3c2019-09-20 14:30:48 -0700211TEST_P(QuicStreamIdManagerTest, ProcessStreamsBlockedTooBig) {
renjietangff4b2b62020-02-12 16:52:32 -0800212 EXPECT_CALL(delegate_, OnStreamIdManagerError(QUIC_STREAMS_BLOCKED_ERROR, _));
rcha8b56e42019-09-20 10:41:48 -0700213 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
214 EXPECT_CALL(delegate_, SendStreamsBlocked(_, _)).Times(0);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700215 QuicStreamCount stream_count =
rcha8b56e42019-09-20 10:41:48 -0700216 stream_id_manager_.incoming_initial_max_open_streams() + 1;
rch9301d3c2019-09-20 14:30:48 -0700217 QuicStreamsBlockedFrame frame(0, stream_count, IsUnidirectional());
rcha8b56e42019-09-20 10:41:48 -0700218 stream_id_manager_.OnStreamsBlockedFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500219}
220
221// Same basic tests as above, but calls
222// QuicStreamIdManager::MaybeIncreaseLargestPeerStreamId directly, avoiding the
223// call chain. The intent is that if there is a problem, the following tests
224// will point to either the stream ID manager or the call chain. They also
225// provide specific, small scale, tests of a public QuicStreamIdManager method.
226// First test make sure that streams with ids below the limit are accepted.
rch9301d3c2019-09-20 14:30:48 -0700227TEST_P(QuicStreamIdManagerTest, IsIncomingStreamIdValidBelowLimit) {
228 QuicStreamId stream_id = GetNthIncomingStreamId(
229 stream_id_manager_.incoming_actual_max_streams() - 2);
renjietangff4b2b62020-02-12 16:52:32 -0800230 EXPECT_CALL(delegate_, OnStreamIdManagerError(_, _)).Times(0);
rcha8b56e42019-09-20 10:41:48 -0700231 EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500232}
233
234// Accept a stream with an ID that equals the limit.
rch9301d3c2019-09-20 14:30:48 -0700235TEST_P(QuicStreamIdManagerTest, IsIncomingStreamIdValidAtLimit) {
236 QuicStreamId stream_id = GetNthIncomingStreamId(
237 stream_id_manager_.incoming_actual_max_streams() - 1);
renjietangff4b2b62020-02-12 16:52:32 -0800238 EXPECT_CALL(delegate_, OnStreamIdManagerError(_, _)).Times(0);
rcha8b56e42019-09-20 10:41:48 -0700239 EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500240}
241
242// Close the connection if the id exceeds the limit.
rch9301d3c2019-09-20 14:30:48 -0700243TEST_P(QuicStreamIdManagerTest, IsIncomingStreamIdInValidAboveLimit) {
244 QuicStreamId stream_id =
245 GetNthIncomingStreamId(stream_id_manager_.incoming_actual_max_streams());
dmcardlecf0bfcf2019-12-13 08:08:21 -0800246 std::string error_details = quiche::QuicheStrCat(
rch9301d3c2019-09-20 14:30:48 -0700247 "Stream id ", stream_id, " would exceed stream count limit 100");
renjietangff4b2b62020-02-12 16:52:32 -0800248 EXPECT_CALL(delegate_,
249 OnStreamIdManagerError(QUIC_INVALID_STREAM_ID, error_details));
rcha8b56e42019-09-20 10:41:48 -0700250 EXPECT_FALSE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500251}
252
rch9301d3c2019-09-20 14:30:48 -0700253TEST_P(QuicStreamIdManagerTest, OnMaxStreamsFrame) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700254 QuicMaxStreamsFrame frame;
renjietang315428e2020-01-27 10:18:12 -0800255 frame.stream_count = 10;
fkastenholz3c4eabf2019-04-22 07:49:59 -0700256
rch9301d3c2019-09-20 14:30:48 -0700257 frame.unidirectional = IsUnidirectional();
258 EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700259 EXPECT_TRUE(stream_id_manager_.OnMaxStreamsFrame(frame));
renjietang315428e2020-01-27 10:18:12 -0800260 EXPECT_EQ(10u, stream_id_manager_.outgoing_max_streams());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700261
262 QuicStreamCount save_outgoing_max_streams =
rcha8b56e42019-09-20 10:41:48 -0700263 stream_id_manager_.outgoing_max_streams();
fkastenholz3c4eabf2019-04-22 07:49:59 -0700264 // Now that there has been one MAX STREAMS frame, we should not
265 // accept a MAX_STREAMS that reduces the limit...
renjietang315428e2020-01-27 10:18:12 -0800266 frame.stream_count = 8;
rch9301d3c2019-09-20 14:30:48 -0700267 frame.unidirectional = IsUnidirectional();
rcha8b56e42019-09-20 10:41:48 -0700268 EXPECT_TRUE(stream_id_manager_.OnMaxStreamsFrame(frame));
fkastenholz3c4eabf2019-04-22 07:49:59 -0700269 // should not change from previous setting.
270 EXPECT_EQ(save_outgoing_max_streams,
rcha8b56e42019-09-20 10:41:48 -0700271 stream_id_manager_.outgoing_max_streams());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700272
273 // A stream count greater than the current limit should increase the limit.
renjietang315428e2020-01-27 10:18:12 -0800274 frame.stream_count = 12;
rch9301d3c2019-09-20 14:30:48 -0700275 EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700276 EXPECT_TRUE(stream_id_manager_.OnMaxStreamsFrame(frame));
fkastenholz3c4eabf2019-04-22 07:49:59 -0700277
renjietang315428e2020-01-27 10:18:12 -0800278 EXPECT_EQ(12u, stream_id_manager_.outgoing_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500279}
280
rch9301d3c2019-09-20 14:30:48 -0700281TEST_P(QuicStreamIdManagerTest, OnStreamsBlockedFrame) {
fkastenholz3c4eabf2019-04-22 07:49:59 -0700282 // Get the current maximum allowed incoming stream count.
283 QuicStreamCount advertised_stream_count =
rcha8b56e42019-09-20 10:41:48 -0700284 stream_id_manager_.incoming_advertised_max_streams();
285
286 // Set the config negotiated to allow frame transmission.
287 stream_id_manager_.OnConfigNegotiated();
fkastenholz56055be2019-09-17 11:17:37 -0700288
fkastenholz3c4eabf2019-04-22 07:49:59 -0700289 QuicStreamsBlockedFrame frame;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500290
rch9301d3c2019-09-20 14:30:48 -0700291 frame.unidirectional = IsUnidirectional();
fkastenholz3c4eabf2019-04-22 07:49:59 -0700292
293 // If the peer is saying it's blocked on the stream count that
QUICHE teama6ef0a62019-03-07 20:34:33 -0500294 // we've advertised, it's a noop since the peer has the correct information.
fkastenholz3c4eabf2019-04-22 07:49:59 -0700295 frame.stream_count = advertised_stream_count;
rcha8b56e42019-09-20 10:41:48 -0700296 EXPECT_CALL(delegate_, SendStreamsBlocked(_, _)).Times(0);
297 EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500298
fkastenholz3c4eabf2019-04-22 07:49:59 -0700299 // If the peer is saying it's blocked on a stream count that is larger
QUICHE teama6ef0a62019-03-07 20:34:33 -0500300 // than what we've advertised, the connection should get closed.
fkastenholz3c4eabf2019-04-22 07:49:59 -0700301 frame.stream_count = advertised_stream_count + 1;
renjietangff4b2b62020-02-12 16:52:32 -0800302 EXPECT_CALL(delegate_, OnStreamIdManagerError(QUIC_STREAMS_BLOCKED_ERROR, _));
rcha8b56e42019-09-20 10:41:48 -0700303 EXPECT_FALSE(stream_id_manager_.OnStreamsBlockedFrame(frame));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500304
fkastenholz3c4eabf2019-04-22 07:49:59 -0700305 // If the peer is saying it's blocked on a count that is less than
306 // our actual count, we send a MAX_STREAMS frame and update
QUICHE teama6ef0a62019-03-07 20:34:33 -0500307 // the advertised value.
308 // First, need to bump up the actual max so there is room for the MAX
fkastenholz3c4eabf2019-04-22 07:49:59 -0700309 // STREAMS frame to send a larger ID.
310 QuicStreamCount actual_stream_count =
rcha8b56e42019-09-20 10:41:48 -0700311 stream_id_manager_.incoming_actual_max_streams();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500312
fkastenholz3c4eabf2019-04-22 07:49:59 -0700313 // Closing a stream will result in the ability to initiate one more
314 // stream
rcha8b56e42019-09-20 10:41:48 -0700315 stream_id_manager_.OnStreamClosed(
316 QuicStreamIdManagerPeer::GetFirstIncomingStreamId(&stream_id_manager_));
fkastenholzd035fc32019-04-23 12:24:02 -0700317 EXPECT_EQ(actual_stream_count + 1u,
rcha8b56e42019-09-20 10:41:48 -0700318 stream_id_manager_.incoming_actual_max_streams());
319 EXPECT_EQ(stream_id_manager_.incoming_actual_max_streams(),
320 stream_id_manager_.incoming_advertised_max_streams() + 1u);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700321
322 // Now simulate receiving a STREAMS_BLOCKED frame...
323 // Changing the actual maximum, above, forces a MAX_STREAMS frame to be
324 // sent, so the logic for that (SendMaxStreamsFrame(), etc) is tested.
325
326 // The STREAMS_BLOCKED frame contains the previous advertised count,
327 // not the one that the peer would have received as a result of the
328 // MAX_STREAMS sent earler.
329 frame.stream_count = advertised_stream_count;
330
rcha8b56e42019-09-20 10:41:48 -0700331 EXPECT_CALL(delegate_,
332 SendMaxStreams(stream_id_manager_.incoming_actual_max_streams(),
rch9301d3c2019-09-20 14:30:48 -0700333 IsUnidirectional()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500334
rcha8b56e42019-09-20 10:41:48 -0700335 EXPECT_TRUE(stream_id_manager_.OnStreamsBlockedFrame(frame));
fkastenholz3c4eabf2019-04-22 07:49:59 -0700336 // Check that the saved frame is correct.
rcha8b56e42019-09-20 10:41:48 -0700337 EXPECT_EQ(stream_id_manager_.incoming_actual_max_streams(),
338 stream_id_manager_.incoming_advertised_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500339}
340
rch9301d3c2019-09-20 14:30:48 -0700341TEST_P(QuicStreamIdManagerTest, GetNextOutgoingStream) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500342 // Number of streams we can open and the first one we should get when
343 // opening...
renjietang7fc869e2019-08-14 11:02:42 -0700344 size_t number_of_streams = kDefaultMaxStreamsPerConnection;
fkastenholz56055be2019-09-17 11:17:37 -0700345
rch9301d3c2019-09-20 14:30:48 -0700346 EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidirectional()));
renjietang315428e2020-01-27 10:18:12 -0800347 stream_id_manager_.SetMaxOpenOutgoingStreams(kDefaultMaxStreamsPerConnection);
rcha8b56e42019-09-20 10:41:48 -0700348
349 stream_id_manager_.OnConfigNegotiated();
fkastenholz56055be2019-09-17 11:17:37 -0700350
QUICHE teama6ef0a62019-03-07 20:34:33 -0500351 QuicStreamId stream_id =
rch9301d3c2019-09-20 14:30:48 -0700352 IsUnidirectional()
353 ? QuicUtils::GetFirstUnidirectionalStreamId(
354 transport_version(), stream_id_manager_.perspective())
355 : QuicUtils::GetFirstBidirectionalStreamId(
356 transport_version(), stream_id_manager_.perspective());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500357
rcha8b56e42019-09-20 10:41:48 -0700358 EXPECT_EQ(number_of_streams, stream_id_manager_.outgoing_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500359 while (number_of_streams) {
rcha8b56e42019-09-20 10:41:48 -0700360 EXPECT_TRUE(stream_id_manager_.CanOpenNextOutgoingStream());
361 EXPECT_EQ(stream_id, stream_id_manager_.GetNextOutgoingStreamId());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500362 stream_id += kV99StreamIdIncrement;
363 number_of_streams--;
364 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500365
366 // If we try to check that the next outgoing stream id is available it should
fkastenholz3c4eabf2019-04-22 07:49:59 -0700367 // A) fail and B) generate a STREAMS_BLOCKED frame.
rch9301d3c2019-09-20 14:30:48 -0700368 EXPECT_CALL(delegate_, SendStreamsBlocked(kDefaultMaxStreamsPerConnection,
369 IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700370 EXPECT_FALSE(stream_id_manager_.CanOpenNextOutgoingStream());
371
QUICHE teama6ef0a62019-03-07 20:34:33 -0500372 // If we try to get the next id (above the limit), it should cause a quic-bug.
373 EXPECT_QUIC_BUG(
rcha8b56e42019-09-20 10:41:48 -0700374 stream_id_manager_.GetNextOutgoingStreamId(),
fkastenholz3c4eabf2019-04-22 07:49:59 -0700375 "Attempt to allocate a new outgoing stream that would exceed the limit");
QUICHE teama6ef0a62019-03-07 20:34:33 -0500376}
377
rch9301d3c2019-09-20 14:30:48 -0700378TEST_P(QuicStreamIdManagerTest, MaybeIncreaseLargestPeerStreamId) {
379 QuicStreamId max_stream_id = GetNthIncomingStreamId(
380 stream_id_manager_.incoming_actual_max_streams() - 1);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700381 EXPECT_TRUE(
rcha8b56e42019-09-20 10:41:48 -0700382 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(max_stream_id));
fkastenholz3c4eabf2019-04-22 07:49:59 -0700383
rch9301d3c2019-09-20 14:30:48 -0700384 QuicStreamId first_stream_id = GetNthIncomingStreamId(0);
385 EXPECT_TRUE(
386 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(first_stream_id));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500387 // A bad stream ID results in a closed connection.
renjietangff4b2b62020-02-12 16:52:32 -0800388 EXPECT_CALL(delegate_, OnStreamIdManagerError(QUIC_INVALID_STREAM_ID, _));
rcha8b56e42019-09-20 10:41:48 -0700389 EXPECT_FALSE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(
fkastenholz3c4eabf2019-04-22 07:49:59 -0700390 max_stream_id + kV99StreamIdIncrement));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500391}
392
rch9301d3c2019-09-20 14:30:48 -0700393TEST_P(QuicStreamIdManagerTest, MaxStreamsWindow) {
rcha8b56e42019-09-20 10:41:48 -0700394 // Set the config negotiated to allow frame transmission.
395 stream_id_manager_.OnConfigNegotiated();
fkastenholz56055be2019-09-17 11:17:37 -0700396
fkastenholz3c4eabf2019-04-22 07:49:59 -0700397 // Test that a MAX_STREAMS frame is generated when the peer has less than
398 // |max_streams_window_| streams left that it can initiate.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500399
fkastenholz3c4eabf2019-04-22 07:49:59 -0700400 // First, open, and then close, max_streams_window_ streams. This will
401 // max_streams_window_ streams available for the peer -- no MAX_STREAMS
QUICHE teama6ef0a62019-03-07 20:34:33 -0500402 // should be sent. The -1 is because the check in
fkastenholz3c4eabf2019-04-22 07:49:59 -0700403 // QuicStreamIdManager::MaybeSendMaxStreamsFrame sends a MAX_STREAMS if the
404 // number of available streams at the peer is <= |max_streams_window_|
rcha8b56e42019-09-20 10:41:48 -0700405 int stream_count = stream_id_manager_.max_streams_window() - 1;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500406
407 // Should not get a control-frame transmission since the peer should have
408 // "plenty" of stream IDs to use.
rcha8b56e42019-09-20 10:41:48 -0700409 EXPECT_CALL(delegate_, SendStreamsBlocked(_, _)).Times(0);
410 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700411
412 // Get the first incoming stream ID to try and allocate.
rch9301d3c2019-09-20 14:30:48 -0700413 QuicStreamId stream_id = GetNthIncomingStreamId(0);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500414 size_t old_available_incoming_streams =
rcha8b56e42019-09-20 10:41:48 -0700415 stream_id_manager_.available_incoming_streams();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500416 while (stream_count) {
rcha8b56e42019-09-20 10:41:48 -0700417 EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500418
fkastenholz3c4eabf2019-04-22 07:49:59 -0700419 // This node should think that the peer believes it has one fewer
420 // stream it can create.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500421 old_available_incoming_streams--;
422 EXPECT_EQ(old_available_incoming_streams,
rcha8b56e42019-09-20 10:41:48 -0700423 stream_id_manager_.available_incoming_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500424
425 stream_count--;
426 stream_id += kV99StreamIdIncrement;
427 }
428
fkastenholz3c4eabf2019-04-22 07:49:59 -0700429 // Now close them, still should get no MAX_STREAMS
rcha8b56e42019-09-20 10:41:48 -0700430 stream_count = stream_id_manager_.max_streams_window();
rch9301d3c2019-09-20 14:30:48 -0700431 stream_id = GetNthIncomingStreamId(0);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700432 QuicStreamCount expected_actual_max =
rcha8b56e42019-09-20 10:41:48 -0700433 stream_id_manager_.incoming_actual_max_streams();
fkastenholz3c4eabf2019-04-22 07:49:59 -0700434 QuicStreamCount expected_advertised_max_streams =
rcha8b56e42019-09-20 10:41:48 -0700435 stream_id_manager_.incoming_advertised_max_streams();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500436 while (stream_count) {
rcha8b56e42019-09-20 10:41:48 -0700437 stream_id_manager_.OnStreamClosed(stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500438 stream_count--;
439 stream_id += kV99StreamIdIncrement;
fkastenholz3c4eabf2019-04-22 07:49:59 -0700440 expected_actual_max++;
441 EXPECT_EQ(expected_actual_max,
rcha8b56e42019-09-20 10:41:48 -0700442 stream_id_manager_.incoming_actual_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500443 // Advertised maximum should remain the same.
fkastenholz3c4eabf2019-04-22 07:49:59 -0700444 EXPECT_EQ(expected_advertised_max_streams,
rcha8b56e42019-09-20 10:41:48 -0700445 stream_id_manager_.incoming_advertised_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500446 }
447
448 // This should not change.
449 EXPECT_EQ(old_available_incoming_streams,
rcha8b56e42019-09-20 10:41:48 -0700450 stream_id_manager_.available_incoming_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500451
fkastenholz3c4eabf2019-04-22 07:49:59 -0700452 // Now whenever we close a stream we should get a MAX_STREAMS frame.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500453 // Above code closed all the open streams, so we have to open/close
rcha8b56e42019-09-20 10:41:48 -0700454 // EXPECT_CALL(delegate_,
455 // SendMaxStreams(stream_id_manager_.incoming_actual_max_streams(),
rch9301d3c2019-09-20 14:30:48 -0700456 // IsUnidirectional()));
457 EXPECT_CALL(delegate_, SendMaxStreams(_, IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700458 EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(stream_id));
459 stream_id_manager_.OnStreamClosed(stream_id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500460}
461
rch9301d3c2019-09-20 14:30:48 -0700462TEST_P(QuicStreamIdManagerTest, StreamsBlockedEdgeConditions) {
rcha8b56e42019-09-20 10:41:48 -0700463 // Set the config negotiated to allow frame transmission.
464 stream_id_manager_.OnConfigNegotiated();
fkastenholz56055be2019-09-17 11:17:37 -0700465
fkastenholz3c4eabf2019-04-22 07:49:59 -0700466 QuicStreamsBlockedFrame frame;
rch9301d3c2019-09-20 14:30:48 -0700467 frame.unidirectional = IsUnidirectional();
fkastenholz3c4eabf2019-04-22 07:49:59 -0700468
469 // Check that receipt of a STREAMS BLOCKED with stream-count = 0 does nothing
470 // when max_allowed_incoming_streams is 0.
rcha8b56e42019-09-20 10:41:48 -0700471 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
472 EXPECT_CALL(delegate_, SendStreamsBlocked(_, _)).Times(0);
473 stream_id_manager_.SetMaxOpenIncomingStreams(0);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700474 frame.stream_count = 0;
rcha8b56e42019-09-20 10:41:48 -0700475 stream_id_manager_.OnStreamsBlockedFrame(frame);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700476
477 // Check that receipt of a STREAMS BLOCKED with stream-count = 0 invokes a
478 // MAX STREAMS, count = 123, when the MaxOpen... is set to 123.
rch9301d3c2019-09-20 14:30:48 -0700479 EXPECT_CALL(delegate_, SendMaxStreams(123u, IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700480 EXPECT_CALL(delegate_, SendStreamsBlocked(_, _)).Times(0);
481 stream_id_manager_.SetMaxOpenIncomingStreams(123);
fkastenholz3c4eabf2019-04-22 07:49:59 -0700482 frame.stream_count = 0;
rcha8b56e42019-09-20 10:41:48 -0700483 stream_id_manager_.OnStreamsBlockedFrame(frame);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500484}
485
rch9301d3c2019-09-20 14:30:48 -0700486TEST_P(QuicStreamIdManagerTest, HoldMaxStreamsFrame) {
rcha8b56e42019-09-20 10:41:48 -0700487 // The config has not been negotiated so the MAX_STREAMS frame will not be
488 // sent.
489 EXPECT_CALL(delegate_, SendMaxStreams(_, _)).Times(0);
fkastenholz56055be2019-09-17 11:17:37 -0700490
rch9301d3c2019-09-20 14:30:48 -0700491 QuicStreamsBlockedFrame frame(1u, 0u, IsUnidirectional());
fkastenholz56055be2019-09-17 11:17:37 -0700492 // Should cause change in pending_max_streams.
rcha8b56e42019-09-20 10:41:48 -0700493 stream_id_manager_.OnStreamsBlockedFrame(frame);
fkastenholz56055be2019-09-17 11:17:37 -0700494
rch9301d3c2019-09-20 14:30:48 -0700495 EXPECT_CALL(delegate_, SendMaxStreams(_, IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700496
497 // MAX_STREAMS will be sent now that the config has been negotiated.
498 stream_id_manager_.OnConfigNegotiated();
fkastenholz56055be2019-09-17 11:17:37 -0700499}
500
rch9301d3c2019-09-20 14:30:48 -0700501TEST_P(QuicStreamIdManagerTest, HoldStreamsBlockedFrameXmit) {
rcha8b56e42019-09-20 10:41:48 -0700502 // We should not see a STREAMS_BLOCKED frame because we're not configured..
503 EXPECT_CALL(delegate_, SendStreamsBlocked(_, _)).Times(0);
fkastenholz56055be2019-09-17 11:17:37 -0700504
505 // Since the stream limit is 0 and no sreams can be created this should return
rcha8b56e42019-09-20 10:41:48 -0700506 // false and have forced a STREAMS_BLOCKED to be queued up, with the
fkastenholz56055be2019-09-17 11:17:37 -0700507 // blocked stream id == 0.
rcha8b56e42019-09-20 10:41:48 -0700508 EXPECT_FALSE(stream_id_manager_.CanOpenNextOutgoingStream());
fkastenholz56055be2019-09-17 11:17:37 -0700509
rcha8b56e42019-09-20 10:41:48 -0700510 // Since the steam limit has not been increased when the config was negotiated
511 // a STREAMS_BLOCKED frame should be sent.
rch9301d3c2019-09-20 14:30:48 -0700512 EXPECT_CALL(delegate_, SendStreamsBlocked(_, IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700513 stream_id_manager_.OnConfigNegotiated();
fkastenholz56055be2019-09-17 11:17:37 -0700514}
515
rch9301d3c2019-09-20 14:30:48 -0700516TEST_P(QuicStreamIdManagerTest, HoldStreamsBlockedFrameNoXmit) {
rcha8b56e42019-09-20 10:41:48 -0700517 // We should not see a STREAMS_BLOCKED frame because we're not configured..
rch9301d3c2019-09-20 14:30:48 -0700518 EXPECT_CALL(delegate_, SendStreamsBlocked(_, IsUnidirectional())).Times(0);
fkastenholz56055be2019-09-17 11:17:37 -0700519
520 // Since the stream limit is 0 and no sreams can be created this should return
rcha8b56e42019-09-20 10:41:48 -0700521 // false and have forced a STREAMS_BLOCKED to be queued up, with the
fkastenholz56055be2019-09-17 11:17:37 -0700522 // blocked stream id == 0.
rcha8b56e42019-09-20 10:41:48 -0700523 EXPECT_FALSE(stream_id_manager_.CanOpenNextOutgoingStream());
fkastenholz56055be2019-09-17 11:17:37 -0700524
rch9301d3c2019-09-20 14:30:48 -0700525 EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700526 stream_id_manager_.SetMaxOpenOutgoingStreams(10);
527 // Since the stream limit has been increase which allows streams to be created
528 // no STREAMS_BLOCKED should be send.
529 stream_id_manager_.OnConfigNegotiated();
fkastenholz56055be2019-09-17 11:17:37 -0700530}
531
rch9301d3c2019-09-20 14:30:48 -0700532TEST_P(QuicStreamIdManagerTest, CheckMaxAllowedOutgoingInitialization) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500533 const size_t kIncomingStreamCount = 123;
rch9301d3c2019-09-20 14:30:48 -0700534 EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700535 stream_id_manager_.SetMaxOpenOutgoingStreams(kIncomingStreamCount);
536 EXPECT_EQ(kIncomingStreamCount, stream_id_manager_.outgoing_max_streams());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500537}
538
fkastenholz3c4eabf2019-04-22 07:49:59 -0700539// Test that a MAX_STREAMS frame is generated when half the stream ids become
QUICHE teama6ef0a62019-03-07 20:34:33 -0500540// available. This has a useful side effect of testing that when streams are
541// closed, the number of available stream ids increases.
rch9301d3c2019-09-20 14:30:48 -0700542TEST_P(QuicStreamIdManagerTest, MaxStreamsSlidingWindow) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500543 // Simulate config being negotiated, causing the limits all to be initialized.
rcha8b56e42019-09-20 10:41:48 -0700544 stream_id_manager_.OnConfigNegotiated();
545
fkastenholz3c4eabf2019-04-22 07:49:59 -0700546 QuicStreamCount first_advert =
rcha8b56e42019-09-20 10:41:48 -0700547 stream_id_manager_.incoming_advertised_max_streams();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500548
fkastenholz3c4eabf2019-04-22 07:49:59 -0700549 // Open/close enough streams to shrink the window without causing a MAX
550 // STREAMS to be generated. The window will open (and a MAX STREAMS generated)
551 // when max_streams_window() stream IDs have been made available. The loop
QUICHE teama6ef0a62019-03-07 20:34:33 -0500552 // will make that many stream IDs available, so the last CloseStream should
rcha8b56e42019-09-20 10:41:48 -0700553
fkastenholz3c4eabf2019-04-22 07:49:59 -0700554 // cause a MAX STREAMS frame to be generated.
rcha8b56e42019-09-20 10:41:48 -0700555 int i = static_cast<int>(stream_id_manager_.max_streams_window());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700556 QuicStreamId id =
rcha8b56e42019-09-20 10:41:48 -0700557 QuicStreamIdManagerPeer::GetFirstIncomingStreamId(&stream_id_manager_);
558 EXPECT_CALL(
559 delegate_,
560 SendMaxStreams(first_advert + stream_id_manager_.max_streams_window(),
rch9301d3c2019-09-20 14:30:48 -0700561 IsUnidirectional()));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500562 while (i) {
rcha8b56e42019-09-20 10:41:48 -0700563 EXPECT_TRUE(stream_id_manager_.MaybeIncreaseLargestPeerStreamId(id));
564 stream_id_manager_.OnStreamClosed(id);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500565 i--;
566 id += kV99StreamIdIncrement;
567 }
QUICHE teama6ef0a62019-03-07 20:34:33 -0500568}
569
rch9301d3c2019-09-20 14:30:48 -0700570TEST_P(QuicStreamIdManagerTest, NewStreamDoesNotExceedLimit) {
571 EXPECT_CALL(delegate_, OnCanCreateNewOutgoingStream(IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700572 stream_id_manager_.SetMaxOpenOutgoingStreams(100);
573 stream_id_manager_.OnConfigNegotiated();
fkastenholz56055be2019-09-17 11:17:37 -0700574
rcha8b56e42019-09-20 10:41:48 -0700575 size_t stream_count = stream_id_manager_.outgoing_max_streams();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500576 EXPECT_NE(0u, stream_count);
rcha8b56e42019-09-20 10:41:48 -0700577
QUICHE teama6ef0a62019-03-07 20:34:33 -0500578 while (stream_count) {
rcha8b56e42019-09-20 10:41:48 -0700579 EXPECT_TRUE(stream_id_manager_.CanOpenNextOutgoingStream());
580 stream_id_manager_.GetNextOutgoingStreamId();
QUICHE teama6ef0a62019-03-07 20:34:33 -0500581 stream_count--;
582 }
fkastenholz3c4eabf2019-04-22 07:49:59 -0700583
rcha8b56e42019-09-20 10:41:48 -0700584 EXPECT_EQ(stream_id_manager_.outgoing_stream_count(),
585 stream_id_manager_.outgoing_max_streams());
fkastenholz3c4eabf2019-04-22 07:49:59 -0700586 // Create another, it should fail. Should also send a STREAMS_BLOCKED
QUICHE teama6ef0a62019-03-07 20:34:33 -0500587 // control frame.
rch9301d3c2019-09-20 14:30:48 -0700588 EXPECT_CALL(delegate_, SendStreamsBlocked(_, IsUnidirectional()));
rcha8b56e42019-09-20 10:41:48 -0700589 EXPECT_FALSE(stream_id_manager_.CanOpenNextOutgoingStream());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500590}
591
rch9301d3c2019-09-20 14:30:48 -0700592TEST_P(QuicStreamIdManagerTest, AvailableStreams) {
rcha8b56e42019-09-20 10:41:48 -0700593 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(
rch9301d3c2019-09-20 14:30:48 -0700594 GetNthIncomingStreamId(3));
595
596 EXPECT_TRUE(stream_id_manager_.IsAvailableStream(GetNthIncomingStreamId(1)));
597 EXPECT_TRUE(stream_id_manager_.IsAvailableStream(GetNthIncomingStreamId(2)));
598 EXPECT_FALSE(stream_id_manager_.IsAvailableStream(GetNthIncomingStreamId(3)));
599 EXPECT_TRUE(stream_id_manager_.IsAvailableStream(GetNthIncomingStreamId(4)));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500600}
601
602// Tests that if MaybeIncreaseLargestPeerStreamId is given an extremely
603// large stream ID (larger than the limit) it is rejected.
604// This is a regression for Chromium bugs 909987 and 910040
rch9301d3c2019-09-20 14:30:48 -0700605TEST_P(QuicStreamIdManagerTest, ExtremeMaybeIncreaseLargestPeerStreamId) {
606 QuicStreamId too_big_stream_id = GetNthIncomingStreamId(
607 stream_id_manager_.incoming_actual_max_streams() + 20);
dmcardlecf0bfcf2019-12-13 08:08:21 -0800608 std::string error_details = quiche::QuicheStrCat(
rch9301d3c2019-09-20 14:30:48 -0700609 "Stream id ", too_big_stream_id, " would exceed stream count limit 100");
nharper46833c32019-05-15 21:33:05 -0700610
renjietangff4b2b62020-02-12 16:52:32 -0800611 EXPECT_CALL(delegate_,
612 OnStreamIdManagerError(QUIC_INVALID_STREAM_ID, error_details));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500613 EXPECT_FALSE(
rcha8b56e42019-09-20 10:41:48 -0700614 stream_id_manager_.MaybeIncreaseLargestPeerStreamId(too_big_stream_id));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500615}
616
QUICHE teama6ef0a62019-03-07 20:34:33 -0500617} // namespace
618} // namespace test
619} // namespace quic