• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "quiche/quic/core/uber_quic_stream_id_manager.h"
6 
7 #include "quiche/quic/core/quic_utils.h"
8 #include "quiche/quic/core/quic_versions.h"
9 #include "quiche/quic/platform/api/quic_test.h"
10 #include "quiche/quic/test_tools/quic_stream_id_manager_peer.h"
11 #include "quiche/quic/test_tools/quic_test_utils.h"
12 
13 using testing::_;
14 using testing::StrictMock;
15 
16 namespace quic {
17 namespace test {
18 namespace {
19 
20 struct TestParams {
TestParamsquic::test::__anon976c35ee0111::TestParams21   explicit TestParams(ParsedQuicVersion version, Perspective perspective)
22       : version(version), perspective(perspective) {}
23 
24   ParsedQuicVersion version;
25   Perspective perspective;
26 };
27 
28 // Used by ::testing::PrintToStringParamName().
PrintToString(const TestParams & p)29 std::string PrintToString(const TestParams& p) {
30   return absl::StrCat(
31       ParsedQuicVersionToString(p.version), "_",
32       (p.perspective == Perspective::IS_CLIENT ? "client" : "server"));
33 }
34 
GetTestParams()35 std::vector<TestParams> GetTestParams() {
36   std::vector<TestParams> params;
37   for (const ParsedQuicVersion& version : AllSupportedVersions()) {
38     if (!version.HasIetfQuicFrames()) {
39       continue;
40     }
41     params.push_back(TestParams(version, Perspective::IS_CLIENT));
42     params.push_back(TestParams(version, Perspective::IS_SERVER));
43   }
44   return params;
45 }
46 
47 class MockDelegate : public QuicStreamIdManager::DelegateInterface {
48  public:
49   MOCK_METHOD(void, SendMaxStreams,
50               (QuicStreamCount stream_count, bool unidirectional), (override));
51 };
52 
53 class UberQuicStreamIdManagerTest : public QuicTestWithParam<TestParams> {
54  protected:
UberQuicStreamIdManagerTest()55   UberQuicStreamIdManagerTest()
56       : manager_(perspective(), version(), &delegate_, 0, 0,
57                  kDefaultMaxStreamsPerConnection,
58                  kDefaultMaxStreamsPerConnection) {}
59 
GetNthClientInitiatedBidirectionalId(int n)60   QuicStreamId GetNthClientInitiatedBidirectionalId(int n) {
61     return QuicUtils::GetFirstBidirectionalStreamId(transport_version(),
62                                                     Perspective::IS_CLIENT) +
63            QuicUtils::StreamIdDelta(transport_version()) * n;
64   }
65 
GetNthClientInitiatedUnidirectionalId(int n)66   QuicStreamId GetNthClientInitiatedUnidirectionalId(int n) {
67     return QuicUtils::GetFirstUnidirectionalStreamId(transport_version(),
68                                                      Perspective::IS_CLIENT) +
69            QuicUtils::StreamIdDelta(transport_version()) * n;
70   }
71 
GetNthServerInitiatedBidirectionalId(int n)72   QuicStreamId GetNthServerInitiatedBidirectionalId(int n) {
73     return QuicUtils::GetFirstBidirectionalStreamId(transport_version(),
74                                                     Perspective::IS_SERVER) +
75            QuicUtils::StreamIdDelta(transport_version()) * n;
76   }
77 
GetNthServerInitiatedUnidirectionalId(int n)78   QuicStreamId GetNthServerInitiatedUnidirectionalId(int n) {
79     return QuicUtils::GetFirstUnidirectionalStreamId(transport_version(),
80                                                      Perspective::IS_SERVER) +
81            QuicUtils::StreamIdDelta(transport_version()) * n;
82   }
83 
GetNthPeerInitiatedBidirectionalStreamId(int n)84   QuicStreamId GetNthPeerInitiatedBidirectionalStreamId(int n) {
85     return ((perspective() == Perspective::IS_SERVER)
86                 ? GetNthClientInitiatedBidirectionalId(n)
87                 : GetNthServerInitiatedBidirectionalId(n));
88   }
GetNthPeerInitiatedUnidirectionalStreamId(int n)89   QuicStreamId GetNthPeerInitiatedUnidirectionalStreamId(int n) {
90     return ((perspective() == Perspective::IS_SERVER)
91                 ? GetNthClientInitiatedUnidirectionalId(n)
92                 : GetNthServerInitiatedUnidirectionalId(n));
93   }
GetNthSelfInitiatedBidirectionalStreamId(int n)94   QuicStreamId GetNthSelfInitiatedBidirectionalStreamId(int n) {
95     return ((perspective() == Perspective::IS_CLIENT)
96                 ? GetNthClientInitiatedBidirectionalId(n)
97                 : GetNthServerInitiatedBidirectionalId(n));
98   }
GetNthSelfInitiatedUnidirectionalStreamId(int n)99   QuicStreamId GetNthSelfInitiatedUnidirectionalStreamId(int n) {
100     return ((perspective() == Perspective::IS_CLIENT)
101                 ? GetNthClientInitiatedUnidirectionalId(n)
102                 : GetNthServerInitiatedUnidirectionalId(n));
103   }
104 
StreamCountToId(QuicStreamCount stream_count,Perspective perspective,bool bidirectional)105   QuicStreamId StreamCountToId(QuicStreamCount stream_count,
106                                Perspective perspective, bool bidirectional) {
107     return ((bidirectional) ? QuicUtils::GetFirstBidirectionalStreamId(
108                                   transport_version(), perspective)
109                             : QuicUtils::GetFirstUnidirectionalStreamId(
110                                   transport_version(), perspective)) +
111            ((stream_count - 1) * QuicUtils::StreamIdDelta(transport_version()));
112   }
113 
version()114   ParsedQuicVersion version() { return GetParam().version; }
transport_version()115   QuicTransportVersion transport_version() {
116     return version().transport_version;
117   }
118 
perspective()119   Perspective perspective() { return GetParam().perspective; }
120 
121   testing::StrictMock<MockDelegate> delegate_;
122   UberQuicStreamIdManager manager_;
123 };
124 
125 INSTANTIATE_TEST_SUITE_P(Tests, UberQuicStreamIdManagerTest,
126                          ::testing::ValuesIn(GetTestParams()),
127                          ::testing::PrintToStringParamName());
128 
TEST_P(UberQuicStreamIdManagerTest,Initialization)129 TEST_P(UberQuicStreamIdManagerTest, Initialization) {
130   EXPECT_EQ(GetNthSelfInitiatedBidirectionalStreamId(0),
131             manager_.next_outgoing_bidirectional_stream_id());
132   EXPECT_EQ(GetNthSelfInitiatedUnidirectionalStreamId(0),
133             manager_.next_outgoing_unidirectional_stream_id());
134 }
135 
TEST_P(UberQuicStreamIdManagerTest,SetMaxOpenOutgoingStreams)136 TEST_P(UberQuicStreamIdManagerTest, SetMaxOpenOutgoingStreams) {
137   const size_t kNumMaxOutgoingStream = 123;
138   // Set the uni- and bi- directional limits to different values to ensure
139   // that they are managed separately.
140   EXPECT_TRUE(manager_.MaybeAllowNewOutgoingBidirectionalStreams(
141       kNumMaxOutgoingStream));
142   EXPECT_TRUE(manager_.MaybeAllowNewOutgoingUnidirectionalStreams(
143       kNumMaxOutgoingStream + 1));
144   EXPECT_EQ(kNumMaxOutgoingStream,
145             manager_.max_outgoing_bidirectional_streams());
146   EXPECT_EQ(kNumMaxOutgoingStream + 1,
147             manager_.max_outgoing_unidirectional_streams());
148   // Check that, for each directionality, we can open the correct number of
149   // streams.
150   int i = kNumMaxOutgoingStream;
151   while (i) {
152     EXPECT_TRUE(manager_.CanOpenNextOutgoingBidirectionalStream());
153     manager_.GetNextOutgoingBidirectionalStreamId();
154     EXPECT_TRUE(manager_.CanOpenNextOutgoingUnidirectionalStream());
155     manager_.GetNextOutgoingUnidirectionalStreamId();
156     i--;
157   }
158   // One more unidirectional
159   EXPECT_TRUE(manager_.CanOpenNextOutgoingUnidirectionalStream());
160   manager_.GetNextOutgoingUnidirectionalStreamId();
161 
162   // Both should be exhausted...
163   EXPECT_FALSE(manager_.CanOpenNextOutgoingUnidirectionalStream());
164   EXPECT_FALSE(manager_.CanOpenNextOutgoingBidirectionalStream());
165 }
166 
TEST_P(UberQuicStreamIdManagerTest,SetMaxOpenIncomingStreams)167 TEST_P(UberQuicStreamIdManagerTest, SetMaxOpenIncomingStreams) {
168   const size_t kNumMaxIncomingStreams = 456;
169   manager_.SetMaxOpenIncomingUnidirectionalStreams(kNumMaxIncomingStreams);
170   // Do +1 for bidirectional to ensure that uni- and bi- get properly set.
171   manager_.SetMaxOpenIncomingBidirectionalStreams(kNumMaxIncomingStreams + 1);
172   EXPECT_EQ(kNumMaxIncomingStreams + 1,
173             manager_.GetMaxAllowdIncomingBidirectionalStreams());
174   EXPECT_EQ(kNumMaxIncomingStreams,
175             manager_.GetMaxAllowdIncomingUnidirectionalStreams());
176   EXPECT_EQ(manager_.max_incoming_bidirectional_streams(),
177             manager_.advertised_max_incoming_bidirectional_streams());
178   EXPECT_EQ(manager_.max_incoming_unidirectional_streams(),
179             manager_.advertised_max_incoming_unidirectional_streams());
180   // Make sure that we can create kNumMaxIncomingStreams incoming unidirectional
181   // streams and kNumMaxIncomingStreams+1 incoming bidirectional streams.
182   size_t i;
183   for (i = 0; i < kNumMaxIncomingStreams; i++) {
184     EXPECT_TRUE(manager_.MaybeIncreaseLargestPeerStreamId(
185         GetNthPeerInitiatedUnidirectionalStreamId(i), nullptr));
186     EXPECT_TRUE(manager_.MaybeIncreaseLargestPeerStreamId(
187         GetNthPeerInitiatedBidirectionalStreamId(i), nullptr));
188   }
189   // Should be able to open the next bidirectional stream
190   EXPECT_TRUE(manager_.MaybeIncreaseLargestPeerStreamId(
191       GetNthPeerInitiatedBidirectionalStreamId(i), nullptr));
192 
193   // We should have exhausted the counts, the next streams should fail
194   std::string error_details;
195   EXPECT_FALSE(manager_.MaybeIncreaseLargestPeerStreamId(
196       GetNthPeerInitiatedUnidirectionalStreamId(i), &error_details));
197   EXPECT_EQ(error_details,
198             absl::StrCat(
199                 "Stream id ", GetNthPeerInitiatedUnidirectionalStreamId(i),
200                 " would exceed stream count limit ", kNumMaxIncomingStreams));
201   EXPECT_FALSE(manager_.MaybeIncreaseLargestPeerStreamId(
202       GetNthPeerInitiatedBidirectionalStreamId(i + 1), &error_details));
203   EXPECT_EQ(error_details,
204             absl::StrCat("Stream id ",
205                          GetNthPeerInitiatedBidirectionalStreamId(i + 1),
206                          " would exceed stream count limit ",
207                          kNumMaxIncomingStreams + 1));
208 }
209 
TEST_P(UberQuicStreamIdManagerTest,GetNextOutgoingStreamId)210 TEST_P(UberQuicStreamIdManagerTest, GetNextOutgoingStreamId) {
211   EXPECT_TRUE(manager_.MaybeAllowNewOutgoingBidirectionalStreams(10));
212   EXPECT_TRUE(manager_.MaybeAllowNewOutgoingUnidirectionalStreams(10));
213   EXPECT_EQ(GetNthSelfInitiatedBidirectionalStreamId(0),
214             manager_.GetNextOutgoingBidirectionalStreamId());
215   EXPECT_EQ(GetNthSelfInitiatedBidirectionalStreamId(1),
216             manager_.GetNextOutgoingBidirectionalStreamId());
217   EXPECT_EQ(GetNthSelfInitiatedUnidirectionalStreamId(0),
218             manager_.GetNextOutgoingUnidirectionalStreamId());
219   EXPECT_EQ(GetNthSelfInitiatedUnidirectionalStreamId(1),
220             manager_.GetNextOutgoingUnidirectionalStreamId());
221 }
222 
TEST_P(UberQuicStreamIdManagerTest,AvailableStreams)223 TEST_P(UberQuicStreamIdManagerTest, AvailableStreams) {
224   EXPECT_TRUE(manager_.MaybeIncreaseLargestPeerStreamId(
225       GetNthPeerInitiatedBidirectionalStreamId(3), nullptr));
226   EXPECT_TRUE(
227       manager_.IsAvailableStream(GetNthPeerInitiatedBidirectionalStreamId(1)));
228   EXPECT_TRUE(
229       manager_.IsAvailableStream(GetNthPeerInitiatedBidirectionalStreamId(2)));
230 
231   EXPECT_TRUE(manager_.MaybeIncreaseLargestPeerStreamId(
232       GetNthPeerInitiatedUnidirectionalStreamId(3), nullptr));
233   EXPECT_TRUE(
234       manager_.IsAvailableStream(GetNthPeerInitiatedUnidirectionalStreamId(1)));
235   EXPECT_TRUE(
236       manager_.IsAvailableStream(GetNthPeerInitiatedUnidirectionalStreamId(2)));
237 }
238 
TEST_P(UberQuicStreamIdManagerTest,MaybeIncreaseLargestPeerStreamId)239 TEST_P(UberQuicStreamIdManagerTest, MaybeIncreaseLargestPeerStreamId) {
240   EXPECT_TRUE(manager_.MaybeIncreaseLargestPeerStreamId(
241       StreamCountToId(manager_.max_incoming_bidirectional_streams(),
242                       QuicUtils::InvertPerspective(perspective()),
243                       /* bidirectional=*/true),
244       nullptr));
245   EXPECT_TRUE(manager_.MaybeIncreaseLargestPeerStreamId(
246       StreamCountToId(manager_.max_incoming_bidirectional_streams(),
247                       QuicUtils::InvertPerspective(perspective()),
248                       /* bidirectional=*/false),
249       nullptr));
250 
251   std::string expected_error_details =
252       perspective() == Perspective::IS_SERVER
253           ? "Stream id 400 would exceed stream count limit 100"
254           : "Stream id 401 would exceed stream count limit 100";
255   std::string error_details;
256 
257   EXPECT_FALSE(manager_.MaybeIncreaseLargestPeerStreamId(
258       StreamCountToId(manager_.max_incoming_bidirectional_streams() + 1,
259                       QuicUtils::InvertPerspective(perspective()),
260                       /* bidirectional=*/true),
261       &error_details));
262   EXPECT_EQ(expected_error_details, error_details);
263   expected_error_details =
264       perspective() == Perspective::IS_SERVER
265           ? "Stream id 402 would exceed stream count limit 100"
266           : "Stream id 403 would exceed stream count limit 100";
267 
268   EXPECT_FALSE(manager_.MaybeIncreaseLargestPeerStreamId(
269       StreamCountToId(manager_.max_incoming_bidirectional_streams() + 1,
270                       QuicUtils::InvertPerspective(perspective()),
271                       /* bidirectional=*/false),
272       &error_details));
273   EXPECT_EQ(expected_error_details, error_details);
274 }
275 
TEST_P(UberQuicStreamIdManagerTest,OnStreamsBlockedFrame)276 TEST_P(UberQuicStreamIdManagerTest, OnStreamsBlockedFrame) {
277   QuicStreamCount stream_count =
278       manager_.advertised_max_incoming_bidirectional_streams() - 1;
279 
280   QuicStreamsBlockedFrame frame(kInvalidControlFrameId, stream_count,
281                                 /*unidirectional=*/false);
282   EXPECT_CALL(delegate_,
283               SendMaxStreams(manager_.max_incoming_bidirectional_streams(),
284                              frame.unidirectional))
285       .Times(0);
286   EXPECT_TRUE(manager_.OnStreamsBlockedFrame(frame, nullptr));
287 
288   stream_count = manager_.advertised_max_incoming_unidirectional_streams() - 1;
289   frame.stream_count = stream_count;
290   frame.unidirectional = true;
291 
292   EXPECT_CALL(delegate_,
293               SendMaxStreams(manager_.max_incoming_unidirectional_streams(),
294                              frame.unidirectional))
295       .Times(0);
296   EXPECT_TRUE(manager_.OnStreamsBlockedFrame(frame, nullptr));
297 }
298 
TEST_P(UberQuicStreamIdManagerTest,SetMaxOpenOutgoingStreamsPlusFrame)299 TEST_P(UberQuicStreamIdManagerTest, SetMaxOpenOutgoingStreamsPlusFrame) {
300   const size_t kNumMaxOutgoingStream = 123;
301   // Set the uni- and bi- directional limits to different values to ensure
302   // that they are managed separately.
303   EXPECT_TRUE(manager_.MaybeAllowNewOutgoingBidirectionalStreams(
304       kNumMaxOutgoingStream));
305   EXPECT_TRUE(manager_.MaybeAllowNewOutgoingUnidirectionalStreams(
306       kNumMaxOutgoingStream + 1));
307   EXPECT_EQ(kNumMaxOutgoingStream,
308             manager_.max_outgoing_bidirectional_streams());
309   EXPECT_EQ(kNumMaxOutgoingStream + 1,
310             manager_.max_outgoing_unidirectional_streams());
311   // Check that, for each directionality, we can open the correct number of
312   // streams.
313   int i = kNumMaxOutgoingStream;
314   while (i) {
315     EXPECT_TRUE(manager_.CanOpenNextOutgoingBidirectionalStream());
316     manager_.GetNextOutgoingBidirectionalStreamId();
317     EXPECT_TRUE(manager_.CanOpenNextOutgoingUnidirectionalStream());
318     manager_.GetNextOutgoingUnidirectionalStreamId();
319     i--;
320   }
321   // One more unidirectional
322   EXPECT_TRUE(manager_.CanOpenNextOutgoingUnidirectionalStream());
323   manager_.GetNextOutgoingUnidirectionalStreamId();
324 
325   // Both should be exhausted...
326   EXPECT_FALSE(manager_.CanOpenNextOutgoingUnidirectionalStream());
327   EXPECT_FALSE(manager_.CanOpenNextOutgoingBidirectionalStream());
328 }
329 
330 }  // namespace
331 }  // namespace test
332 }  // namespace quic
333