• 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/legacy_quic_stream_id_manager.h"
6 
7 #include <utility>
8 
9 #include "absl/strings/str_cat.h"
10 #include "quiche/quic/core/quic_types.h"
11 #include "quiche/quic/core/quic_utils.h"
12 #include "quiche/quic/core/quic_versions.h"
13 #include "quiche/quic/platform/api/quic_test.h"
14 #include "quiche/quic/test_tools/quic_session_peer.h"
15 #include "quiche/quic/test_tools/quic_test_utils.h"
16 
17 namespace quic {
18 namespace test {
19 namespace {
20 
21 using testing::_;
22 using testing::StrictMock;
23 
24 struct TestParams {
TestParamsquic::test::__anon230298c40111::TestParams25   TestParams(ParsedQuicVersion version, Perspective perspective)
26       : version(version), perspective(perspective) {}
27 
28   ParsedQuicVersion version;
29   Perspective perspective;
30 };
31 
32 // Used by ::testing::PrintToStringParamName().
PrintToString(const TestParams & p)33 std::string PrintToString(const TestParams& p) {
34   return absl::StrCat(
35       ParsedQuicVersionToString(p.version),
36       (p.perspective == Perspective::IS_CLIENT ? "Client" : "Server"));
37 }
38 
GetTestParams()39 std::vector<TestParams> GetTestParams() {
40   std::vector<TestParams> params;
41   for (ParsedQuicVersion version : AllSupportedVersions()) {
42     for (auto perspective : {Perspective::IS_CLIENT, Perspective::IS_SERVER}) {
43       // LegacyQuicStreamIdManager is only used when IETF QUIC frames are not
44       // presented.
45       if (!VersionHasIetfQuicFrames(version.transport_version)) {
46         params.push_back(TestParams(version, perspective));
47       }
48     }
49   }
50   return params;
51 }
52 
53 class LegacyQuicStreamIdManagerTest : public QuicTestWithParam<TestParams> {
54  public:
LegacyQuicStreamIdManagerTest()55   LegacyQuicStreamIdManagerTest()
56       : manager_(GetParam().perspective, GetParam().version.transport_version,
57                  kDefaultMaxStreamsPerConnection,
58                  kDefaultMaxStreamsPerConnection) {}
59 
60  protected:
GetNthPeerInitiatedId(int n)61   QuicStreamId GetNthPeerInitiatedId(int n) {
62     if (GetParam().perspective == Perspective::IS_SERVER) {
63       return QuicUtils::GetFirstBidirectionalStreamId(
64                  GetParam().version.transport_version, Perspective::IS_CLIENT) +
65              2 * n;
66     } else {
67       return 2 + 2 * n;
68     }
69   }
70 
71   LegacyQuicStreamIdManager manager_;
72 };
73 
74 INSTANTIATE_TEST_SUITE_P(Tests, LegacyQuicStreamIdManagerTest,
75                          ::testing::ValuesIn(GetTestParams()),
76                          ::testing::PrintToStringParamName());
77 
TEST_P(LegacyQuicStreamIdManagerTest,CanOpenNextOutgoingStream)78 TEST_P(LegacyQuicStreamIdManagerTest, CanOpenNextOutgoingStream) {
79   for (size_t i = 0; i < manager_.max_open_outgoing_streams() - 1; ++i) {
80     manager_.ActivateStream(/*is_incoming=*/false);
81   }
82   EXPECT_TRUE(manager_.CanOpenNextOutgoingStream());
83   manager_.ActivateStream(/*is_incoming=*/false);
84   EXPECT_FALSE(manager_.CanOpenNextOutgoingStream());
85 }
86 
TEST_P(LegacyQuicStreamIdManagerTest,CanOpenIncomingStream)87 TEST_P(LegacyQuicStreamIdManagerTest, CanOpenIncomingStream) {
88   for (size_t i = 0; i < manager_.max_open_incoming_streams() - 1; ++i) {
89     manager_.ActivateStream(/*is_incoming=*/true);
90   }
91   EXPECT_TRUE(manager_.CanOpenIncomingStream());
92   manager_.ActivateStream(/*is_incoming=*/true);
93   EXPECT_FALSE(manager_.CanOpenIncomingStream());
94 }
95 
TEST_P(LegacyQuicStreamIdManagerTest,AvailableStreams)96 TEST_P(LegacyQuicStreamIdManagerTest, AvailableStreams) {
97   ASSERT_TRUE(
98       manager_.MaybeIncreaseLargestPeerStreamId(GetNthPeerInitiatedId(3)));
99   EXPECT_TRUE(manager_.IsAvailableStream(GetNthPeerInitiatedId(1)));
100   EXPECT_TRUE(manager_.IsAvailableStream(GetNthPeerInitiatedId(2)));
101   ASSERT_TRUE(
102       manager_.MaybeIncreaseLargestPeerStreamId(GetNthPeerInitiatedId(2)));
103   ASSERT_TRUE(
104       manager_.MaybeIncreaseLargestPeerStreamId(GetNthPeerInitiatedId(1)));
105 }
106 
TEST_P(LegacyQuicStreamIdManagerTest,MaxAvailableStreams)107 TEST_P(LegacyQuicStreamIdManagerTest, MaxAvailableStreams) {
108   // Test that the server closes the connection if a client makes too many data
109   // streams available.  The server accepts slightly more than the negotiated
110   // stream limit to deal with rare cases where a client FIN/RST is lost.
111   const size_t kMaxStreamsForTest = 10;
112   const size_t kAvailableStreamLimit = manager_.MaxAvailableStreams();
113   EXPECT_EQ(
114       manager_.max_open_incoming_streams() * kMaxAvailableStreamsMultiplier,
115       manager_.MaxAvailableStreams());
116   // The protocol specification requires that there can be at least 10 times
117   // as many available streams as the connection's maximum open streams.
118   EXPECT_LE(10 * kMaxStreamsForTest, kAvailableStreamLimit);
119 
120   EXPECT_TRUE(
121       manager_.MaybeIncreaseLargestPeerStreamId(GetNthPeerInitiatedId(0)));
122 
123   // Establish available streams up to the server's limit.
124   const int kLimitingStreamId =
125       GetNthPeerInitiatedId(kAvailableStreamLimit + 1);
126   // This exceeds the stream limit. In versions other than 99
127   // this is allowed. Version 99 hews to the IETF spec and does
128   // not allow it.
129   EXPECT_TRUE(manager_.MaybeIncreaseLargestPeerStreamId(kLimitingStreamId));
130 
131   // This forces stream kLimitingStreamId + 2 to become available, which
132   // violates the quota.
133   EXPECT_FALSE(
134       manager_.MaybeIncreaseLargestPeerStreamId(kLimitingStreamId + 2 * 2));
135 }
136 
TEST_P(LegacyQuicStreamIdManagerTest,MaximumAvailableOpenedStreams)137 TEST_P(LegacyQuicStreamIdManagerTest, MaximumAvailableOpenedStreams) {
138   QuicStreamId stream_id = GetNthPeerInitiatedId(0);
139   EXPECT_TRUE(manager_.MaybeIncreaseLargestPeerStreamId(stream_id));
140 
141   EXPECT_TRUE(manager_.MaybeIncreaseLargestPeerStreamId(
142       stream_id + 2 * (manager_.max_open_incoming_streams() - 1)));
143 }
144 
TEST_P(LegacyQuicStreamIdManagerTest,TooManyAvailableStreams)145 TEST_P(LegacyQuicStreamIdManagerTest, TooManyAvailableStreams) {
146   QuicStreamId stream_id = GetNthPeerInitiatedId(0);
147   EXPECT_TRUE(manager_.MaybeIncreaseLargestPeerStreamId(stream_id));
148 
149   // A stream ID which is too large to create.
150   QuicStreamId stream_id2 =
151       GetNthPeerInitiatedId(2 * manager_.MaxAvailableStreams() + 4);
152   EXPECT_FALSE(manager_.MaybeIncreaseLargestPeerStreamId(stream_id2));
153 }
154 
TEST_P(LegacyQuicStreamIdManagerTest,ManyAvailableStreams)155 TEST_P(LegacyQuicStreamIdManagerTest, ManyAvailableStreams) {
156   // When max_open_streams_ is 200, should be able to create 200 streams
157   // out-of-order, that is, creating the one with the largest stream ID first.
158   manager_.set_max_open_incoming_streams(200);
159   QuicStreamId stream_id = GetNthPeerInitiatedId(0);
160   EXPECT_TRUE(manager_.MaybeIncreaseLargestPeerStreamId(stream_id));
161 
162   // Create the largest stream ID of a threatened total of 200 streams.
163   // GetNth... starts at 0, so for 200 streams, get the 199th.
164   EXPECT_TRUE(
165       manager_.MaybeIncreaseLargestPeerStreamId(GetNthPeerInitiatedId(199)));
166 }
167 
TEST_P(LegacyQuicStreamIdManagerTest,TestMaxIncomingAndOutgoingStreamsAllowed)168 TEST_P(LegacyQuicStreamIdManagerTest,
169        TestMaxIncomingAndOutgoingStreamsAllowed) {
170   EXPECT_EQ(manager_.max_open_incoming_streams(),
171             kDefaultMaxStreamsPerConnection);
172   EXPECT_EQ(manager_.max_open_outgoing_streams(),
173             kDefaultMaxStreamsPerConnection);
174 }
175 
176 }  // namespace
177 }  // namespace test
178 }  // namespace quic
179