| #ifndef QUICHE_HTTP2_ADAPTER_NGHTTP2_TEST_UTILS_H_ |
| #define QUICHE_HTTP2_ADAPTER_NGHTTP2_TEST_UTILS_H_ |
| |
| #include <cstdint> |
| #include <vector> |
| |
| #include "absl/strings/string_view.h" |
| #include "http2/adapter/http2_protocol.h" |
| #include "http2/adapter/nghttp2.h" |
| #include "common/platform/api/quiche_export.h" |
| #include "common/platform/api/quiche_test.h" |
| |
| namespace http2 { |
| namespace adapter { |
| namespace test { |
| |
| // A simple class that can easily be adapted to act as a nghttp2_data_source. |
| class QUICHE_NO_EXPORT TestDataSource { |
| public: |
| explicit TestDataSource(absl::string_view data) : data_(std::string(data)) {} |
| |
| absl::string_view ReadNext(size_t size) { |
| const size_t to_send = std::min(size, remaining_.size()); |
| auto ret = remaining_.substr(0, to_send); |
| remaining_.remove_prefix(to_send); |
| return ret; |
| } |
| |
| size_t SelectPayloadLength(size_t max_length) { |
| return std::min(max_length, remaining_.size()); |
| } |
| |
| nghttp2_data_provider MakeDataProvider() { |
| return nghttp2_data_provider{ |
| .source = {.ptr = this}, |
| .read_callback = [](nghttp2_session*, int32_t, uint8_t*, size_t length, |
| uint32_t* data_flags, nghttp2_data_source* source, |
| void*) -> ssize_t { |
| *data_flags |= NGHTTP2_DATA_FLAG_NO_COPY; |
| auto* s = static_cast<TestDataSource*>(source->ptr); |
| if (!s->is_data_available()) { |
| return NGHTTP2_ERR_DEFERRED; |
| } |
| const ssize_t ret = s->SelectPayloadLength(length); |
| if (ret < static_cast<ssize_t>(length)) { |
| *data_flags |= NGHTTP2_DATA_FLAG_EOF; |
| } |
| return ret; |
| }}; |
| } |
| |
| bool is_data_available() const { return is_data_available_; } |
| void set_is_data_available(bool value) { is_data_available_ = value; } |
| |
| private: |
| const std::string data_; |
| absl::string_view remaining_ = data_; |
| bool is_data_available_ = true; |
| }; |
| |
| // Matchers for nghttp2 data types. |
| testing::Matcher<const nghttp2_frame_hd*> HasFrameHeader( |
| uint32_t streamid, uint8_t type, const testing::Matcher<int> flags); |
| testing::Matcher<const nghttp2_frame_hd&> HasFrameHeaderRef( |
| uint32_t streamid, uint8_t type, const testing::Matcher<int> flags); |
| |
| testing::Matcher<const nghttp2_frame*> IsData( |
| const testing::Matcher<uint32_t> stream_id, |
| const testing::Matcher<size_t> length, const testing::Matcher<int> flags); |
| |
| testing::Matcher<const nghttp2_frame*> IsHeaders( |
| const testing::Matcher<uint32_t> stream_id, |
| const testing::Matcher<int> flags, const testing::Matcher<int> category); |
| |
| testing::Matcher<const nghttp2_frame*> IsRstStream( |
| const testing::Matcher<uint32_t> stream_id, |
| const testing::Matcher<uint32_t> error_code); |
| |
| testing::Matcher<const nghttp2_frame*> IsSettings( |
| const testing::Matcher<std::vector<Http2Setting>> values); |
| |
| testing::Matcher<const nghttp2_frame*> IsPing( |
| const testing::Matcher<uint64_t> id); |
| |
| testing::Matcher<const nghttp2_frame*> IsPingAck( |
| const testing::Matcher<uint64_t> id); |
| |
| testing::Matcher<const nghttp2_frame*> IsGoAway( |
| const testing::Matcher<uint32_t> last_stream_id, |
| const testing::Matcher<uint32_t> error_code, |
| const testing::Matcher<absl::string_view> opaque_data); |
| |
| testing::Matcher<const nghttp2_frame*> IsWindowUpdate( |
| const testing::Matcher<uint32_t> delta); |
| |
| } // namespace test |
| } // namespace adapter |
| } // namespace http2 |
| |
| #endif // QUICHE_HTTP2_ADAPTER_NGHTTP2_TEST_UTILS_H_ |