blob: f162ad79ad9eaa25671c9f38c37ccc401862fa0c [file] [log] [blame]
QUICHE teamfd50a402018-12-07 22:54:05 -05001// 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#ifndef QUICHE_HTTP2_TOOLS_RANDOM_DECODER_TEST_H_
6#define QUICHE_HTTP2_TOOLS_RANDOM_DECODER_TEST_H_
7
8// RandomDecoderTest is a base class for tests of decoding various kinds
9// of HTTP/2 and HPACK encodings.
10
11// TODO(jamessynge): Move more methods into .cc file.
12
13#include <stddef.h>
14
15#include <cstdint>
16#include <functional>
17#include <memory>
18#include <type_traits>
19
QUICHE teamfd50a402018-12-07 22:54:05 -050020#include "testing/gtest/include/gtest/gtest.h"
21#include "net/third_party/quiche/src/http2/decoder/decode_buffer.h"
22#include "net/third_party/quiche/src/http2/decoder/decode_status.h"
QUICHE team61940b42019-03-07 23:32:27 -050023#include "net/third_party/quiche/src/http2/platform/api/http2_logging.h"
QUICHE teamfd50a402018-12-07 22:54:05 -050024#include "net/third_party/quiche/src/http2/platform/api/http2_string.h"
25#include "net/third_party/quiche/src/http2/platform/api/http2_string_piece.h"
26#include "net/third_party/quiche/src/http2/platform/api/http2_test_helpers.h"
27#include "net/third_party/quiche/src/http2/test_tools/http2_random.h"
28
29namespace http2 {
30namespace test {
31
32// Some helpers.
33
34template <typename T, size_t N>
35Http2StringPiece ToStringPiece(T (&data)[N]) {
36 return Http2StringPiece(reinterpret_cast<const char*>(data), N * sizeof(T));
37}
38
39// Overwrite the enum with some random value, probably not a valid value for
40// the enum type, but which fits into its storage.
41template <typename T,
42 typename E = typename std::enable_if<std::is_enum<T>::value>::type>
43void CorruptEnum(T* out, Http2Random* rng) {
44 // Per cppreference.com, if the destination type of a static_cast is
45 // smaller than the source type (i.e. type of r and uint32 below), the
46 // resulting value is the smallest unsigned value equal to the source value
47 // modulo 2^n, where n is the number of bits used to represent the
48 // destination type unsigned U.
49 using underlying_type_T = typename std::underlying_type<T>::type;
50 using unsigned_underlying_type_T =
51 typename std::make_unsigned<underlying_type_T>::type;
52 auto r = static_cast<unsigned_underlying_type_T>(rng->Rand32());
53 *out = static_cast<T>(r);
54}
55
56// Base class for tests of the ability to decode a sequence of bytes with
57// various boundaries between the DecodeBuffers provided to the decoder.
58class RandomDecoderTest : public ::testing::Test {
59 public:
60 // SelectSize returns the size of the next DecodeBuffer to be passed to the
61 // decoder. Note that RandomDecoderTest allows that size to be zero, though
62 // some decoders can't deal with that on the first byte, hence the |first|
63 // parameter.
64 typedef std::function<size_t(bool first, size_t offset, size_t remaining)>
65 SelectSize;
66
67 // Validator returns an AssertionResult so test can do:
68 // EXPECT_THAT(DecodeAndValidate(..., validator));
69 typedef ::testing::AssertionResult AssertionResult;
70 typedef std::function<AssertionResult(const DecodeBuffer& input,
71 DecodeStatus status)>
72 Validator;
73 typedef std::function<AssertionResult()> NoArgValidator;
74
75 RandomDecoderTest();
76
77 protected:
78 // TODO(jamessynge): Modify StartDecoding, etc. to (somehow) return
79 // AssertionResult so that the VERIFY_* methods exported from
80 // gunit_helpers.h can be widely used.
81
82 // Start decoding; call allows sub-class to Reset the decoder, or deal with
83 // the first byte if that is done in a unique fashion. Might be called with
84 // a zero byte buffer.
85 virtual DecodeStatus StartDecoding(DecodeBuffer* db) = 0;
86
87 // Resume decoding of the input after a prior call to StartDecoding, and
88 // possibly many calls to ResumeDecoding.
89 virtual DecodeStatus ResumeDecoding(DecodeBuffer* db) = 0;
90
91 // Return true if a decode status of kDecodeDone indicates that
92 // decoding should stop.
93 virtual bool StopDecodeOnDone();
94
95 // Decode buffer |original| until we run out of input, or kDecodeDone is
96 // returned by the decoder AND StopDecodeOnDone() returns true. Segments
97 // (i.e. cuts up) the original DecodeBuffer into (potentially) smaller buffers
98 // by calling |select_size| to decide how large each buffer should be.
99 // We do this to test the ability to deal with arbitrary boundaries, as might
100 // happen in transport.
101 // Returns the final DecodeStatus.
102 DecodeStatus DecodeSegments(DecodeBuffer* original,
103 const SelectSize& select_size);
104
105 // Decode buffer |original| until we run out of input, or kDecodeDone is
106 // returned by the decoder AND StopDecodeOnDone() returns true. Segments
107 // (i.e. cuts up) the original DecodeBuffer into (potentially) smaller buffers
108 // by calling |select_size| to decide how large each buffer should be.
109 // We do this to test the ability to deal with arbitrary boundaries, as might
110 // happen in transport.
111 // Invokes |validator| with the final decode status and the original decode
112 // buffer, with the cursor advanced as far as has been consumed by the decoder
113 // and returns validator's result.
114 ::testing::AssertionResult DecodeSegmentsAndValidate(
115 DecodeBuffer* original,
116 const SelectSize& select_size,
117 const Validator& validator) {
118 DecodeStatus status = DecodeSegments(original, select_size);
119 VERIFY_AND_RETURN_SUCCESS(validator(*original, status));
120 }
121
122 // Returns a SelectSize function for fast decoding, i.e. passing all that
123 // is available to the decoder.
124 static SelectSize SelectRemaining() {
125 return [](bool first, size_t offset, size_t remaining) -> size_t {
126 return remaining;
127 };
128 }
129
130 // Returns a SelectSize function for decoding a single byte at a time.
131 static SelectSize SelectOne() {
132 return
133 [](bool first, size_t offset, size_t remaining) -> size_t { return 1; };
134 }
135
136 // Returns a SelectSize function for decoding a single byte at a time, where
137 // zero byte buffers are also allowed. Alternates between zero and one.
138 static SelectSize SelectZeroAndOne(bool return_non_zero_on_first);
139
140 // Returns a SelectSize function for decoding random sized segments.
141 SelectSize SelectRandom(bool return_non_zero_on_first);
142
143 // Decode |original| multiple times, with different segmentations of the
144 // decode buffer, validating after each decode, and confirming that they
145 // each decode the same amount. Returns on the first failure, else returns
146 // success.
147 AssertionResult DecodeAndValidateSeveralWays(DecodeBuffer* original,
148 bool return_non_zero_on_first,
149 const Validator& validator);
150
151 static Validator ToValidator(std::nullptr_t) {
152 return [](const DecodeBuffer& input, DecodeStatus status) {
153 return ::testing::AssertionSuccess();
154 };
155 }
156
157 static Validator ToValidator(const Validator& validator) {
158 if (validator == nullptr) {
159 return ToValidator(nullptr);
160 }
161 return validator;
162 }
163
164 static Validator ToValidator(const NoArgValidator& validator) {
165 if (validator == nullptr) {
166 return ToValidator(nullptr);
167 }
168 return [validator](const DecodeBuffer& input, DecodeStatus status) {
169 return validator();
170 };
171 }
172
173 // Wraps a validator with another validator
174 // that first checks that the DecodeStatus is kDecodeDone and
175 // that the DecodeBuffer is empty.
176 // TODO(jamessynge): Replace this overload with the next, as using this method
177 // usually means that the wrapped function doesn't need to be passed the
178 // DecodeBuffer nor the DecodeStatus.
179 static Validator ValidateDoneAndEmpty(const Validator& wrapped) {
180 return [wrapped](const DecodeBuffer& input,
181 DecodeStatus status) -> AssertionResult {
182 VERIFY_EQ(status, DecodeStatus::kDecodeDone);
183 VERIFY_EQ(0u, input.Remaining()) << "\nOffset=" << input.Offset();
184 if (wrapped) {
185 return wrapped(input, status);
186 }
187 return ::testing::AssertionSuccess();
188 };
189 }
190 static Validator ValidateDoneAndEmpty(NoArgValidator wrapped) {
191 return [wrapped](const DecodeBuffer& input,
192 DecodeStatus status) -> AssertionResult {
193 VERIFY_EQ(status, DecodeStatus::kDecodeDone);
194 VERIFY_EQ(0u, input.Remaining()) << "\nOffset=" << input.Offset();
195 if (wrapped) {
196 return wrapped();
197 }
198 return ::testing::AssertionSuccess();
199 };
200 }
201 static Validator ValidateDoneAndEmpty() {
202 NoArgValidator validator;
203 return ValidateDoneAndEmpty(validator);
204 }
205
206 // Wraps a validator with another validator
207 // that first checks that the DecodeStatus is kDecodeDone and
208 // that the DecodeBuffer has the expected offset.
209 // TODO(jamessynge): Replace this overload with the next, as using this method
210 // usually means that the wrapped function doesn't need to be passed the
211 // DecodeBuffer nor the DecodeStatus.
212 static Validator ValidateDoneAndOffset(uint32_t offset,
213 const Validator& wrapped) {
214 return [wrapped, offset](const DecodeBuffer& input,
215 DecodeStatus status) -> AssertionResult {
216 VERIFY_EQ(status, DecodeStatus::kDecodeDone);
217 VERIFY_EQ(offset, input.Offset()) << "\nRemaining=" << input.Remaining();
218 if (wrapped) {
219 return wrapped(input, status);
220 }
221 return ::testing::AssertionSuccess();
222 };
223 }
224 static Validator ValidateDoneAndOffset(uint32_t offset,
225 NoArgValidator wrapped) {
226 return [wrapped, offset](const DecodeBuffer& input,
227 DecodeStatus status) -> AssertionResult {
228 VERIFY_EQ(status, DecodeStatus::kDecodeDone);
229 VERIFY_EQ(offset, input.Offset()) << "\nRemaining=" << input.Remaining();
230 if (wrapped) {
231 return wrapped();
232 }
233 return ::testing::AssertionSuccess();
234 };
235 }
236 static Validator ValidateDoneAndOffset(uint32_t offset) {
237 NoArgValidator validator;
238 return ValidateDoneAndOffset(offset, validator);
239 }
240
241 // Expose |random_| as Http2Random so callers don't have to care about which
242 // sub-class of Http2Random is used, nor can they rely on the specific
243 // sub-class that RandomDecoderTest uses.
244 Http2Random& Random() { return random_; }
245 Http2Random* RandomPtr() { return &random_; }
246
247 uint32_t RandStreamId();
248
249 bool stop_decode_on_done_ = true;
250
251 private:
252 Http2Random random_;
253};
254
255} // namespace test
256} // namespace http2
257
258#endif // QUICHE_HTTP2_TOOLS_RANDOM_DECODER_TEST_H_