OLD | NEW |
| (Empty) |
1 // Copyright 2016 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 "net/http2/http2_structures.h" | |
6 | |
7 // Tests are focused on Http2FrameHeader because it has by far the most | |
8 // methods of any of the structures. | |
9 // Note that EXPECT.*DEATH tests are slow (a fork is probably involved). | |
10 | |
11 // And in case you're wondering, yes, these are ridiculously thorough tests, | |
12 // but believe it or not, I've found stupid bugs this way. | |
13 | |
14 #include <memory> | |
15 #include <ostream> | |
16 #include <sstream> | |
17 #include <tuple> | |
18 #include <type_traits> | |
19 #include <vector> | |
20 | |
21 #include "base/template_util.h" | |
22 #include "net/http2/http2_structures_test_util.h" | |
23 #include "net/http2/tools/failure.h" | |
24 #include "net/http2/tools/http2_random.h" | |
25 #include "testing/gmock/include/gmock/gmock.h" | |
26 #include "testing/gtest/include/gtest/gtest.h" | |
27 | |
28 using ::testing::AssertionResult; | |
29 using ::testing::AssertionSuccess; | |
30 using ::testing::Combine; | |
31 using ::testing::EndsWith; | |
32 using ::testing::HasSubstr; | |
33 using ::testing::MatchesRegex; | |
34 using ::testing::Not; | |
35 using ::testing::Values; | |
36 using ::testing::ValuesIn; | |
37 | |
38 namespace net { | |
39 namespace test { | |
40 namespace { | |
41 | |
42 template <typename E> | |
43 E IncrementEnum(E e) { | |
44 typedef typename base::underlying_type<E>::type I; | |
45 return static_cast<E>(1 + static_cast<I>(e)); | |
46 } | |
47 | |
48 #if GTEST_HAS_DEATH_TEST && !defined(NDEBUG) | |
49 std::vector<Http2FrameType> ValidFrameTypes() { | |
50 std::vector<Http2FrameType> valid_types{Http2FrameType::DATA}; | |
51 while (valid_types.back() != Http2FrameType::ALTSVC) { | |
52 valid_types.push_back(IncrementEnum(valid_types.back())); | |
53 } | |
54 return valid_types; | |
55 } | |
56 #endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG) | |
57 | |
58 TEST(Http2FrameHeaderTest, Constructor) { | |
59 Http2Random random; | |
60 uint8_t frame_type = 0; | |
61 do { | |
62 // Only the payload length is DCHECK'd in the constructor, so we need to | |
63 // make sure it is a "uint24". | |
64 uint32_t payload_length = random.Rand32() & 0xffffff; | |
65 Http2FrameType type = static_cast<Http2FrameType>(frame_type); | |
66 uint8_t flags = random.Rand8(); | |
67 uint32_t stream_id = random.Rand32(); | |
68 | |
69 Http2FrameHeader v(payload_length, type, flags, stream_id); | |
70 | |
71 EXPECT_EQ(payload_length, v.payload_length); | |
72 EXPECT_EQ(type, v.type); | |
73 EXPECT_EQ(flags, v.flags); | |
74 EXPECT_EQ(stream_id, v.stream_id); | |
75 } while (frame_type++ == 255); | |
76 | |
77 #if GTEST_HAS_DEATH_TEST && !defined(NDEBUG) | |
78 EXPECT_DEBUG_DEATH(Http2FrameHeader(0x01000000, Http2FrameType::DATA, 0, 1), | |
79 "payload_length"); | |
80 #endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG) | |
81 } | |
82 | |
83 TEST(Http2FrameHeaderTest, Eq) { | |
84 Http2Random random; | |
85 uint32_t payload_length = random.Rand32() & 0xffffff; | |
86 Http2FrameType type = static_cast<Http2FrameType>(random.Rand8()); | |
87 | |
88 uint8_t flags = random.Rand8(); | |
89 uint32_t stream_id = random.Rand32(); | |
90 | |
91 Http2FrameHeader v(payload_length, type, flags, stream_id); | |
92 | |
93 EXPECT_EQ(payload_length, v.payload_length); | |
94 EXPECT_EQ(type, v.type); | |
95 EXPECT_EQ(flags, v.flags); | |
96 EXPECT_EQ(stream_id, v.stream_id); | |
97 | |
98 Http2FrameHeader u(0, type, ~flags, stream_id); | |
99 | |
100 EXPECT_NE(u, v); | |
101 EXPECT_NE(v, u); | |
102 EXPECT_FALSE(u == v); | |
103 EXPECT_FALSE(v == u); | |
104 EXPECT_TRUE(u != v); | |
105 EXPECT_TRUE(v != u); | |
106 | |
107 u = v; | |
108 | |
109 EXPECT_EQ(u, v); | |
110 EXPECT_EQ(v, u); | |
111 EXPECT_TRUE(u == v); | |
112 EXPECT_TRUE(v == u); | |
113 EXPECT_FALSE(u != v); | |
114 EXPECT_FALSE(v != u); | |
115 } | |
116 | |
117 #if GTEST_HAS_DEATH_TEST && !defined(NDEBUG) | |
118 // The tests of the valid frame types include EXPECT_DEBUG_DEATH, which is | |
119 // quite slow, so using value parameterized tests in order to allow sharding. | |
120 class Http2FrameHeaderTypeAndFlagTest | |
121 : public ::testing::TestWithParam< | |
122 std::tuple<Http2FrameType, Http2FrameFlag>> { | |
123 protected: | |
124 Http2FrameHeaderTypeAndFlagTest() | |
125 : type_(std::get<0>(GetParam())), flags_(std::get<1>(GetParam())) { | |
126 LOG(INFO) << "Frame type: " << type_; | |
127 LOG(INFO) << "Frame flags: " << Http2FrameFlagsToString(type_, flags_); | |
128 } | |
129 | |
130 const Http2FrameType type_; | |
131 const Http2FrameFlag flags_; | |
132 }; | |
133 | |
134 class IsEndStreamTest : public Http2FrameHeaderTypeAndFlagTest {}; | |
135 INSTANTIATE_TEST_CASE_P(IsEndStream, | |
136 IsEndStreamTest, | |
137 Combine(ValuesIn(ValidFrameTypes()), | |
138 Values(~Http2FrameFlag::FLAG_END_STREAM, | |
139 0xff))); | |
140 TEST_P(IsEndStreamTest, IsEndStream) { | |
141 const bool is_set = (flags_ & Http2FrameFlag::FLAG_END_STREAM) == | |
142 Http2FrameFlag::FLAG_END_STREAM; | |
143 LOG(INFO) << "is_set=" << is_set; | |
144 Http2FrameHeader v(0, type_, flags_, 0); | |
145 switch (type_) { | |
146 case Http2FrameType::DATA: | |
147 case Http2FrameType::HEADERS: | |
148 EXPECT_EQ(is_set, v.IsEndStream()) << v; | |
149 if (is_set) { | |
150 EXPECT_THAT(v.FlagsToString(), MatchesRegex(".*\\|?END_STREAM\\|.*")); | |
151 } else { | |
152 EXPECT_THAT(v.FlagsToString(), Not(HasSubstr("END_STREAM"))); | |
153 } | |
154 v.RetainFlags(Http2FrameFlag::FLAG_END_STREAM); | |
155 EXPECT_EQ(is_set, v.IsEndStream()) << v; | |
156 { | |
157 std::stringstream s; | |
158 s << v; | |
159 EXPECT_EQ(v.ToString(), s.str()); | |
160 if (is_set) { | |
161 EXPECT_THAT(s.str(), HasSubstr("flags=END_STREAM,")); | |
162 } else { | |
163 EXPECT_THAT(s.str(), HasSubstr("flags=,")); | |
164 } | |
165 } | |
166 break; | |
167 default: | |
168 EXPECT_DEBUG_DEATH(v.IsEndStream(), "DATA.*HEADERS") << v; | |
169 } | |
170 } | |
171 | |
172 class IsACKTest : public Http2FrameHeaderTypeAndFlagTest {}; | |
173 INSTANTIATE_TEST_CASE_P(IsAck, | |
174 IsACKTest, | |
175 Combine(ValuesIn(ValidFrameTypes()), | |
176 Values(~Http2FrameFlag::FLAG_ACK, 0xff))); | |
177 TEST_P(IsACKTest, IsAck) { | |
178 const bool is_set = | |
179 (flags_ & Http2FrameFlag::FLAG_ACK) == Http2FrameFlag::FLAG_ACK; | |
180 LOG(INFO) << "is_set=" << is_set; | |
181 Http2FrameHeader v(0, type_, flags_, 0); | |
182 switch (type_) { | |
183 case Http2FrameType::SETTINGS: | |
184 case Http2FrameType::PING: | |
185 EXPECT_EQ(is_set, v.IsAck()) << v; | |
186 if (is_set) { | |
187 EXPECT_THAT(v.FlagsToString(), MatchesRegex(".*\\|?ACK\\|.*")); | |
188 } else { | |
189 EXPECT_THAT(v.FlagsToString(), Not(HasSubstr("ACK"))); | |
190 } | |
191 v.RetainFlags(Http2FrameFlag::FLAG_ACK); | |
192 EXPECT_EQ(is_set, v.IsAck()) << v; | |
193 { | |
194 std::stringstream s; | |
195 s << v; | |
196 EXPECT_EQ(v.ToString(), s.str()); | |
197 if (is_set) { | |
198 EXPECT_THAT(s.str(), HasSubstr("flags=ACK,")); | |
199 } else { | |
200 EXPECT_THAT(s.str(), HasSubstr("flags=,")); | |
201 } | |
202 } | |
203 break; | |
204 default: | |
205 EXPECT_DEBUG_DEATH(v.IsAck(), "SETTINGS.*PING") << v; | |
206 } | |
207 } | |
208 | |
209 class IsEndHeadersTest : public Http2FrameHeaderTypeAndFlagTest {}; | |
210 INSTANTIATE_TEST_CASE_P(IsEndHeaders, | |
211 IsEndHeadersTest, | |
212 Combine(ValuesIn(ValidFrameTypes()), | |
213 Values(~Http2FrameFlag::FLAG_END_HEADERS, | |
214 0xff))); | |
215 TEST_P(IsEndHeadersTest, IsEndHeaders) { | |
216 const bool is_set = (flags_ & Http2FrameFlag::FLAG_END_HEADERS) == | |
217 Http2FrameFlag::FLAG_END_HEADERS; | |
218 LOG(INFO) << "is_set=" << is_set; | |
219 Http2FrameHeader v(0, type_, flags_, 0); | |
220 switch (type_) { | |
221 case Http2FrameType::HEADERS: | |
222 case Http2FrameType::PUSH_PROMISE: | |
223 case Http2FrameType::CONTINUATION: | |
224 EXPECT_EQ(is_set, v.IsEndHeaders()) << v; | |
225 if (is_set) { | |
226 EXPECT_THAT(v.FlagsToString(), MatchesRegex(".*\\|?END_HEADERS\\|.*")); | |
227 } else { | |
228 EXPECT_THAT(v.FlagsToString(), Not(HasSubstr("END_HEADERS"))); | |
229 } | |
230 v.RetainFlags(Http2FrameFlag::FLAG_END_HEADERS); | |
231 EXPECT_EQ(is_set, v.IsEndHeaders()) << v; | |
232 { | |
233 std::stringstream s; | |
234 s << v; | |
235 EXPECT_EQ(v.ToString(), s.str()); | |
236 if (is_set) { | |
237 EXPECT_THAT(s.str(), HasSubstr("flags=END_HEADERS,")); | |
238 } else { | |
239 EXPECT_THAT(s.str(), HasSubstr("flags=,")); | |
240 } | |
241 } | |
242 break; | |
243 default: | |
244 EXPECT_DEBUG_DEATH(v.IsEndHeaders(), | |
245 "HEADERS.*PUSH_PROMISE.*CONTINUATION") | |
246 << v; | |
247 } | |
248 } | |
249 | |
250 class IsPaddedTest : public Http2FrameHeaderTypeAndFlagTest {}; | |
251 INSTANTIATE_TEST_CASE_P(IsPadded, | |
252 IsPaddedTest, | |
253 Combine(ValuesIn(ValidFrameTypes()), | |
254 Values(~Http2FrameFlag::FLAG_PADDED, 0xff))); | |
255 TEST_P(IsPaddedTest, IsPadded) { | |
256 const bool is_set = | |
257 (flags_ & Http2FrameFlag::FLAG_PADDED) == Http2FrameFlag::FLAG_PADDED; | |
258 LOG(INFO) << "is_set=" << is_set; | |
259 Http2FrameHeader v(0, type_, flags_, 0); | |
260 switch (type_) { | |
261 case Http2FrameType::DATA: | |
262 case Http2FrameType::HEADERS: | |
263 case Http2FrameType::PUSH_PROMISE: | |
264 EXPECT_EQ(is_set, v.IsPadded()) << v; | |
265 if (is_set) { | |
266 EXPECT_THAT(v.FlagsToString(), MatchesRegex(".*\\|?PADDED\\|.*")); | |
267 } else { | |
268 EXPECT_THAT(v.FlagsToString(), Not(HasSubstr("PADDED"))); | |
269 } | |
270 v.RetainFlags(Http2FrameFlag::FLAG_PADDED); | |
271 EXPECT_EQ(is_set, v.IsPadded()) << v; | |
272 { | |
273 std::stringstream s; | |
274 s << v; | |
275 EXPECT_EQ(v.ToString(), s.str()); | |
276 if (is_set) { | |
277 EXPECT_THAT(s.str(), HasSubstr("flags=PADDED,")); | |
278 } else { | |
279 EXPECT_THAT(s.str(), HasSubstr("flags=,")); | |
280 } | |
281 } | |
282 break; | |
283 default: | |
284 EXPECT_DEBUG_DEATH(v.IsPadded(), "DATA.*HEADERS.*PUSH_PROMISE") << v; | |
285 } | |
286 } | |
287 | |
288 class HasPriorityTest : public Http2FrameHeaderTypeAndFlagTest {}; | |
289 INSTANTIATE_TEST_CASE_P(HasPriority, | |
290 HasPriorityTest, | |
291 Combine(ValuesIn(ValidFrameTypes()), | |
292 Values(~Http2FrameFlag::FLAG_PRIORITY, 0xff))); | |
293 TEST_P(HasPriorityTest, HasPriority) { | |
294 const bool is_set = | |
295 (flags_ & Http2FrameFlag::FLAG_PRIORITY) == Http2FrameFlag::FLAG_PRIORITY; | |
296 LOG(INFO) << "is_set=" << is_set; | |
297 Http2FrameHeader v(0, type_, flags_, 0); | |
298 switch (type_) { | |
299 case Http2FrameType::HEADERS: | |
300 EXPECT_EQ(is_set, v.HasPriority()) << v; | |
301 if (is_set) { | |
302 EXPECT_THAT(v.FlagsToString(), MatchesRegex(".*\\|?PRIORITY\\|.*")); | |
303 } else { | |
304 EXPECT_THAT(v.FlagsToString(), Not(HasSubstr("PRIORITY"))); | |
305 } | |
306 v.RetainFlags(Http2FrameFlag::FLAG_PRIORITY); | |
307 EXPECT_EQ(is_set, v.HasPriority()) << v; | |
308 { | |
309 std::stringstream s; | |
310 s << v; | |
311 EXPECT_EQ(v.ToString(), s.str()); | |
312 if (is_set) { | |
313 EXPECT_THAT(s.str(), HasSubstr("flags=PRIORITY,")); | |
314 } else { | |
315 EXPECT_THAT(s.str(), HasSubstr("flags=,")); | |
316 } | |
317 } | |
318 break; | |
319 default: | |
320 EXPECT_DEBUG_DEATH(v.HasPriority(), "HEADERS") << v; | |
321 } | |
322 } | |
323 | |
324 TEST(Http2PriorityFieldsTest, Constructor) { | |
325 Http2Random random; | |
326 uint32_t stream_dependency = random.Rand32() & StreamIdMask(); | |
327 uint32_t weight = 1 + random.Rand8(); | |
328 bool is_exclusive = random.OneIn(2); | |
329 | |
330 Http2PriorityFields v(stream_dependency, weight, is_exclusive); | |
331 | |
332 EXPECT_EQ(stream_dependency, v.stream_dependency); | |
333 EXPECT_EQ(weight, v.weight); | |
334 EXPECT_EQ(is_exclusive, v.is_exclusive); | |
335 | |
336 // The high-bit must not be set on the stream id. | |
337 EXPECT_DEBUG_DEATH( | |
338 Http2PriorityFields(stream_dependency | 0x80000000, weight, is_exclusive), | |
339 "31-bit"); | |
340 | |
341 // The weight must be in the range 1-256. | |
342 EXPECT_DEBUG_DEATH(Http2PriorityFields(stream_dependency, 0, is_exclusive), | |
343 "too small"); | |
344 EXPECT_DEBUG_DEATH( | |
345 Http2PriorityFields(stream_dependency, weight + 256, is_exclusive), | |
346 "too large"); | |
347 } | |
348 #endif // GTEST_HAS_DEATH_TEST && !defined(NDEBUG) | |
349 | |
350 TEST(Http2RstStreamFieldsTest, IsSupported) { | |
351 Http2RstStreamFields v{Http2ErrorCode::HTTP2_NO_ERROR}; | |
352 EXPECT_TRUE(v.IsSupportedErrorCode()) << v; | |
353 | |
354 Http2RstStreamFields u{static_cast<Http2ErrorCode>(~0)}; | |
355 EXPECT_FALSE(u.IsSupportedErrorCode()) << v; | |
356 } | |
357 | |
358 TEST(Http2SettingFieldsTest, Misc) { | |
359 Http2Random random; | |
360 Http2SettingsParameter parameter = | |
361 static_cast<Http2SettingsParameter>(random.Rand16()); | |
362 uint32_t value = random.Rand32(); | |
363 | |
364 Http2SettingFields v(parameter, value); | |
365 | |
366 EXPECT_EQ(v, v); | |
367 EXPECT_EQ(parameter, v.parameter); | |
368 EXPECT_EQ(value, v.value); | |
369 | |
370 if (static_cast<uint16_t>(parameter) < 7) { | |
371 EXPECT_TRUE(v.IsSupportedParameter()) << v; | |
372 } else { | |
373 EXPECT_FALSE(v.IsSupportedParameter()) << v; | |
374 } | |
375 | |
376 Http2SettingFields u(parameter, ~value); | |
377 EXPECT_NE(v, u); | |
378 EXPECT_EQ(v.parameter, u.parameter); | |
379 EXPECT_NE(v.value, u.value); | |
380 | |
381 Http2SettingFields w(IncrementEnum(parameter), value); | |
382 EXPECT_NE(v, w); | |
383 EXPECT_NE(v.parameter, w.parameter); | |
384 EXPECT_EQ(v.value, w.value); | |
385 | |
386 Http2SettingFields x(Http2SettingsParameter::MAX_FRAME_SIZE, 123); | |
387 std::stringstream s; | |
388 s << x; | |
389 EXPECT_EQ("parameter=MAX_FRAME_SIZE, value=123", s.str()); | |
390 } | |
391 | |
392 TEST(Http2PushPromiseTest, Misc) { | |
393 Http2Random random; | |
394 uint32_t promised_stream_id = random.Rand32() & StreamIdMask(); | |
395 | |
396 Http2PushPromiseFields v{promised_stream_id}; | |
397 EXPECT_EQ(promised_stream_id, v.promised_stream_id); | |
398 EXPECT_EQ(v, v); | |
399 | |
400 std::stringstream s1; | |
401 s1 << "promised_stream_id=" << promised_stream_id; | |
402 std::stringstream s2; | |
403 s2 << v; | |
404 EXPECT_EQ(s1.str(), s2.str()); | |
405 | |
406 // High-bit is reserved, but not used, so we can set it. | |
407 promised_stream_id |= 0x80000000; | |
408 Http2PushPromiseFields w{promised_stream_id}; | |
409 EXPECT_EQ(w, w); | |
410 EXPECT_NE(v, w); | |
411 | |
412 v.promised_stream_id = promised_stream_id; | |
413 EXPECT_EQ(v, w); | |
414 } | |
415 | |
416 TEST(Http2GoAwayFieldsTest, Misc) { | |
417 Http2Random random; | |
418 uint32_t last_stream_id = random.Rand32() & StreamIdMask(); | |
419 Http2ErrorCode error_code = static_cast<Http2ErrorCode>(random.Rand32()); | |
420 | |
421 Http2GoAwayFields v(last_stream_id, error_code); | |
422 EXPECT_EQ(v, v); | |
423 EXPECT_EQ(last_stream_id, v.last_stream_id); | |
424 EXPECT_EQ(error_code, v.error_code); | |
425 | |
426 if (static_cast<uint32_t>(error_code) < 14) { | |
427 EXPECT_TRUE(v.IsSupportedErrorCode()) << v; | |
428 } else { | |
429 EXPECT_FALSE(v.IsSupportedErrorCode()) << v; | |
430 } | |
431 | |
432 Http2GoAwayFields u(~last_stream_id, error_code); | |
433 EXPECT_NE(v, u); | |
434 EXPECT_NE(v.last_stream_id, u.last_stream_id); | |
435 EXPECT_EQ(v.error_code, u.error_code); | |
436 } | |
437 | |
438 TEST(Http2WindowUpdateTest, Misc) { | |
439 Http2Random random; | |
440 uint32_t window_size_increment = random.Rand32() & UInt31Mask(); | |
441 | |
442 Http2WindowUpdateFields v{window_size_increment}; | |
443 EXPECT_EQ(window_size_increment, v.window_size_increment); | |
444 EXPECT_EQ(v, v); | |
445 | |
446 std::stringstream s1; | |
447 s1 << "window_size_increment=" << window_size_increment; | |
448 std::stringstream s2; | |
449 s2 << v; | |
450 EXPECT_EQ(s1.str(), s2.str()); | |
451 | |
452 // High-bit is reserved, but not used, so we can set it. | |
453 window_size_increment |= 0x80000000; | |
454 Http2WindowUpdateFields w{window_size_increment}; | |
455 EXPECT_EQ(w, w); | |
456 EXPECT_NE(v, w); | |
457 | |
458 v.window_size_increment = window_size_increment; | |
459 EXPECT_EQ(v, w); | |
460 } | |
461 | |
462 TEST(Http2AltSvcTest, Misc) { | |
463 Http2Random random; | |
464 uint16_t origin_length = random.Rand16(); | |
465 | |
466 Http2AltSvcFields v{origin_length}; | |
467 EXPECT_EQ(origin_length, v.origin_length); | |
468 EXPECT_EQ(v, v); | |
469 | |
470 std::stringstream s1; | |
471 s1 << "origin_length=" << origin_length; | |
472 std::stringstream s2; | |
473 s2 << v; | |
474 EXPECT_EQ(s1.str(), s2.str()); | |
475 | |
476 Http2AltSvcFields w{++origin_length}; | |
477 EXPECT_EQ(w, w); | |
478 EXPECT_NE(v, w); | |
479 | |
480 v.origin_length = w.origin_length; | |
481 EXPECT_EQ(v, w); | |
482 } | |
483 | |
484 } // namespace | |
485 } // namespace test | |
486 } // namespace net | |
OLD | NEW |