/proc/self/cwd/test/common/quic/test_utils.h
Line | Count | Source (jump to first uncovered line) |
1 | | #pragma once |
2 | | |
3 | | #include "envoy/common/optref.h" |
4 | | |
5 | | #include "source/common/quic/envoy_quic_client_connection.h" |
6 | | #include "source/common/quic/envoy_quic_client_session.h" |
7 | | #include "source/common/quic/envoy_quic_proof_verifier.h" |
8 | | #include "source/common/quic/envoy_quic_server_connection.h" |
9 | | #include "source/common/quic/envoy_quic_utils.h" |
10 | | #include "source/common/quic/quic_filter_manager_connection_impl.h" |
11 | | #include "source/common/stats/isolated_store_impl.h" |
12 | | |
13 | | #include "test/test_common/environment.h" |
14 | | #include "test/test_common/utility.h" |
15 | | |
16 | | #include "quiche/quic/core/http/quic_spdy_session.h" |
17 | | #include "quiche/quic/core/qpack/qpack_encoder.h" |
18 | | #include "quiche/quic/core/quic_utils.h" |
19 | | #include "quiche/quic/test_tools/crypto_test_utils.h" |
20 | | #include "quiche/quic/test_tools/first_flight.h" |
21 | | #include "quiche/quic/test_tools/qpack/qpack_test_utils.h" |
22 | | #include "quiche/quic/test_tools/quic_config_peer.h" |
23 | | #include "quiche/quic/test_tools/quic_test_utils.h" |
24 | | |
25 | | namespace Envoy { |
26 | | namespace Quic { |
27 | | |
28 | | class MockEnvoyQuicServerConnection : public EnvoyQuicServerConnection { |
29 | | public: |
30 | | MockEnvoyQuicServerConnection(quic::QuicConnectionHelperInterface& helper, |
31 | | quic::QuicAlarmFactory& alarm_factory, |
32 | | quic::QuicPacketWriter& writer, |
33 | | const quic::ParsedQuicVersionVector& supported_versions, |
34 | | Network::Socket& listen_socket, |
35 | | quic::ConnectionIdGeneratorInterface& generator) |
36 | | : MockEnvoyQuicServerConnection( |
37 | | helper, alarm_factory, writer, |
38 | | quic::QuicSocketAddress(quic::QuicIpAddress::Any4(), 12345), |
39 | | quic::QuicSocketAddress(quic::QuicIpAddress::Loopback4(), 12345), supported_versions, |
40 | 0 | listen_socket, generator) {} |
41 | | |
42 | | MockEnvoyQuicServerConnection( |
43 | | quic::QuicConnectionHelperInterface& helper, quic::QuicAlarmFactory& alarm_factory, |
44 | | quic::QuicPacketWriter& writer, quic::QuicSocketAddress self_address, |
45 | | quic::QuicSocketAddress peer_address, const quic::ParsedQuicVersionVector& supported_versions, |
46 | | Network::Socket& listen_socket, quic::ConnectionIdGeneratorInterface& generator) |
47 | | : EnvoyQuicServerConnection( |
48 | | quic::test::TestConnectionId(), self_address, peer_address, helper, alarm_factory, |
49 | | &writer, /*owns_writer=*/false, supported_versions, |
50 | | createServerConnectionSocket(listen_socket.ioHandle(), self_address, peer_address, |
51 | | "example.com", "h3-29"), |
52 | 0 | generator, nullptr) {} |
53 | | |
54 | 0 | Network::Connection::ConnectionStats& connectionStats() const { |
55 | 0 | return QuicNetworkConnection::connectionStats(); |
56 | 0 | } |
57 | | |
58 | | MOCK_METHOD(void, SendConnectionClosePacket, |
59 | | (quic::QuicErrorCode, quic::QuicIetfTransportErrorCodes, const std::string&)); |
60 | | MOCK_METHOD(bool, SendControlFrame, (const quic::QuicFrame& frame)); |
61 | | MOCK_METHOD(quic::MessageStatus, SendMessage, |
62 | | (quic::QuicMessageId, absl::Span<quiche::QuicheMemSlice>, bool)); |
63 | | MOCK_METHOD(void, dumpState, (std::ostream&, int), (const)); |
64 | | }; |
65 | | |
66 | | class MockEnvoyQuicClientConnection : public EnvoyQuicClientConnection { |
67 | | public: |
68 | | MockEnvoyQuicClientConnection(const quic::QuicConnectionId& server_connection_id, |
69 | | quic::QuicConnectionHelperInterface& helper, |
70 | | quic::QuicAlarmFactory& alarm_factory, |
71 | | quic::QuicPacketWriter* writer, bool owns_writer, |
72 | | const quic::ParsedQuicVersionVector& supported_versions, |
73 | | Event::Dispatcher& dispatcher, |
74 | | Network::ConnectionSocketPtr&& connection_socket, |
75 | | quic::ConnectionIdGeneratorInterface& generator) |
76 | | : EnvoyQuicClientConnection(server_connection_id, helper, alarm_factory, writer, owns_writer, |
77 | | supported_versions, dispatcher, std::move(connection_socket), |
78 | 0 | generator) {} |
79 | | |
80 | | MOCK_METHOD(quic::MessageStatus, SendMessage, |
81 | | (quic::QuicMessageId, absl::Span<quiche::QuicheMemSlice>, bool)); |
82 | | }; |
83 | | |
84 | | class TestQuicCryptoStream : public quic::test::MockQuicCryptoStream { |
85 | | public: |
86 | | explicit TestQuicCryptoStream(quic::QuicSession* session) |
87 | 0 | : quic::test::MockQuicCryptoStream(session) {} |
88 | | |
89 | 0 | bool encryption_established() const override { return true; } |
90 | | }; |
91 | | |
92 | | class MockEnvoyQuicSession : public quic::QuicSpdySession, public QuicFilterManagerConnectionImpl { |
93 | | public: |
94 | | MockEnvoyQuicSession(const quic::QuicConfig& config, |
95 | | const quic::ParsedQuicVersionVector& supported_versions, |
96 | | EnvoyQuicServerConnection* connection, Event::Dispatcher& dispatcher, |
97 | | uint32_t send_buffer_limit) |
98 | | : quic::QuicSpdySession(connection, /*visitor=*/nullptr, config, supported_versions), |
99 | | QuicFilterManagerConnectionImpl( |
100 | | *connection, connection->connection_id(), dispatcher, send_buffer_limit, {nullptr}, |
101 | | std::make_unique<StreamInfo::StreamInfoImpl>( |
102 | | dispatcher.timeSource(), |
103 | | connection->connectionSocket()->connectionInfoProviderSharedPtr())), |
104 | 0 | crypto_stream_(std::make_unique<TestQuicCryptoStream>(this)) {} |
105 | | |
106 | 0 | void Initialize() override { |
107 | 0 | quic::QuicSpdySession::Initialize(); |
108 | 0 | initialized_ = true; |
109 | 0 | } |
110 | | |
111 | | // From QuicSession. |
112 | | MOCK_METHOD(quic::QuicSpdyStream*, CreateIncomingStream, (quic::QuicStreamId id)); |
113 | | MOCK_METHOD(quic::QuicSpdyStream*, CreateIncomingStream, (quic::PendingStream * pending)); |
114 | | MOCK_METHOD(quic::QuicSpdyStream*, CreateOutgoingBidirectionalStream, ()); |
115 | | MOCK_METHOD(quic::QuicSpdyStream*, CreateOutgoingUnidirectionalStream, ()); |
116 | | MOCK_METHOD(bool, ShouldCreateIncomingStream, (quic::QuicStreamId id)); |
117 | | MOCK_METHOD(bool, ShouldCreateOutgoingBidirectionalStream, ()); |
118 | | MOCK_METHOD(bool, ShouldCreateOutgoingUnidirectionalStream, ()); |
119 | | MOCK_METHOD(quic::QuicConsumedData, WritevData, |
120 | | (quic::QuicStreamId id, size_t write_length, quic::QuicStreamOffset offset, |
121 | | quic::StreamSendingState state, quic::TransmissionType type, |
122 | | quic::EncryptionLevel level)); |
123 | | MOCK_METHOD(bool, ShouldYield, (quic::QuicStreamId id)); |
124 | | MOCK_METHOD(void, MaybeSendRstStreamFrame, |
125 | | (quic::QuicStreamId id, quic::QuicResetStreamError error, |
126 | | quic::QuicStreamOffset bytes_written)); |
127 | | MOCK_METHOD(void, MaybeSendStopSendingFrame, |
128 | | (quic::QuicStreamId id, quic::QuicResetStreamError error)); |
129 | | MOCK_METHOD(void, dumpState, (std::ostream&, int), (const)); |
130 | | |
131 | 0 | absl::string_view requestedServerName() const override { |
132 | 0 | return {GetCryptoStream()->crypto_negotiated_params().sni}; |
133 | 0 | } |
134 | | |
135 | 0 | quic::QuicCryptoStream* GetMutableCryptoStream() override { return crypto_stream_.get(); } |
136 | | |
137 | 0 | const quic::QuicCryptoStream* GetCryptoStream() const override { return crypto_stream_.get(); } |
138 | | |
139 | | using quic::QuicSpdySession::ActivateStream; |
140 | | |
141 | | protected: |
142 | 0 | quic::HttpDatagramSupport LocalHttpDatagramSupport() override { |
143 | 0 | return quic::HttpDatagramSupport::kRfc; |
144 | 0 | } |
145 | 0 | bool hasDataToWrite() override { return HasDataToWrite(); } |
146 | 0 | const quic::QuicConnection* quicConnection() const override { |
147 | 0 | return initialized_ ? connection() : nullptr; |
148 | 0 | } |
149 | 0 | quic::QuicConnection* quicConnection() override { return initialized_ ? connection() : nullptr; } |
150 | | |
151 | | private: |
152 | | std::unique_ptr<quic::QuicCryptoStream> crypto_stream_; |
153 | | }; |
154 | | |
155 | | class TestQuicCryptoClientStream : public quic::QuicCryptoClientStream { |
156 | | public: |
157 | | TestQuicCryptoClientStream(const quic::QuicServerId& server_id, quic::QuicSession* session, |
158 | | std::unique_ptr<quic::ProofVerifyContext> verify_context, |
159 | | quic::QuicCryptoClientConfig* crypto_config, |
160 | | ProofHandler* proof_handler, bool has_application_state) |
161 | | : quic::QuicCryptoClientStream(server_id, session, std::move(verify_context), crypto_config, |
162 | 0 | proof_handler, has_application_state) {} |
163 | | |
164 | 0 | bool encryption_established() const override { return true; } |
165 | | }; |
166 | | |
167 | | class TestQuicCryptoClientStreamFactory : public EnvoyQuicCryptoClientStreamFactoryInterface { |
168 | | public: |
169 | | std::unique_ptr<quic::QuicCryptoClientStreamBase> |
170 | | createEnvoyQuicCryptoClientStream(const quic::QuicServerId& server_id, quic::QuicSession* session, |
171 | | std::unique_ptr<quic::ProofVerifyContext> verify_context, |
172 | | quic::QuicCryptoClientConfig* crypto_config, |
173 | | quic::QuicCryptoClientStream::ProofHandler* proof_handler, |
174 | 0 | bool has_application_state) override { |
175 | 0 | last_verify_context_ = *verify_context; |
176 | 0 | return std::make_unique<TestQuicCryptoClientStream>(server_id, session, |
177 | 0 | std::move(verify_context), crypto_config, |
178 | 0 | proof_handler, has_application_state); |
179 | 0 | } |
180 | | |
181 | 0 | OptRef<quic::ProofVerifyContext> lastVerifyContext() const { return last_verify_context_; } |
182 | | |
183 | | private: |
184 | | OptRef<quic::ProofVerifyContext> last_verify_context_; |
185 | | }; |
186 | | |
187 | | class IsolatedStoreProvider { |
188 | | protected: |
189 | | Stats::IsolatedStoreImpl stats_store_; |
190 | | }; |
191 | | |
192 | | class MockEnvoyQuicClientSession : public IsolatedStoreProvider, public EnvoyQuicClientSession { |
193 | | public: |
194 | | MockEnvoyQuicClientSession(const quic::QuicConfig& config, |
195 | | const quic::ParsedQuicVersionVector& supported_versions, |
196 | | std::unique_ptr<EnvoyQuicClientConnection> connection, |
197 | | Event::Dispatcher& dispatcher, uint32_t send_buffer_limit, |
198 | | EnvoyQuicCryptoClientStreamFactoryInterface& crypto_stream_factory) |
199 | | : EnvoyQuicClientSession(config, supported_versions, std::move(connection), |
200 | | quic::QuicServerId("example.com", 443, false), |
201 | | std::make_shared<quic::QuicCryptoClientConfig>( |
202 | | quic::test::crypto_test_utils::ProofVerifierForTesting()), |
203 | | dispatcher, send_buffer_limit, crypto_stream_factory, |
204 | 0 | quic_stat_names_, {}, *stats_store_.rootScope(), nullptr) {} |
205 | | |
206 | 0 | void Initialize() override { |
207 | 0 | EnvoyQuicClientSession::Initialize(); |
208 | 0 | initialized_ = true; |
209 | 0 | } |
210 | | |
211 | | // From QuicSession. |
212 | | MOCK_METHOD(quic::QuicSpdyClientStream*, CreateIncomingStream, (quic::QuicStreamId id)); |
213 | | MOCK_METHOD(quic::QuicSpdyClientStream*, CreateIncomingStream, (quic::PendingStream * pending)); |
214 | | MOCK_METHOD(quic::QuicSpdyClientStream*, CreateOutgoingBidirectionalStream, ()); |
215 | | MOCK_METHOD(quic::QuicSpdyClientStream*, CreateOutgoingUnidirectionalStream, ()); |
216 | | MOCK_METHOD(bool, ShouldCreateIncomingStream, (quic::QuicStreamId id)); |
217 | | MOCK_METHOD(bool, ShouldCreateOutgoingBidirectionalStream, ()); |
218 | | MOCK_METHOD(bool, ShouldCreateOutgoingUnidirectionalStream, ()); |
219 | | MOCK_METHOD(quic::QuicConsumedData, WritevData, |
220 | | (quic::QuicStreamId id, size_t write_length, quic::QuicStreamOffset offset, |
221 | | quic::StreamSendingState state, quic::TransmissionType type, |
222 | | quic::EncryptionLevel level)); |
223 | | MOCK_METHOD(bool, ShouldYield, (quic::QuicStreamId id)); |
224 | | MOCK_METHOD(void, dumpState, (std::ostream&, int), (const)); |
225 | | |
226 | 0 | absl::string_view requestedServerName() const override { |
227 | 0 | return {GetCryptoStream()->crypto_negotiated_params().sni}; |
228 | 0 | } |
229 | | |
230 | | using quic::QuicSession::closed_streams; |
231 | | using quic::QuicSpdySession::ActivateStream; |
232 | | |
233 | | protected: |
234 | 0 | quic::HttpDatagramSupport LocalHttpDatagramSupport() override { |
235 | 0 | return quic::HttpDatagramSupport::kRfc; |
236 | 0 | } |
237 | 0 | bool hasDataToWrite() override { return HasDataToWrite(); } |
238 | 0 | const quic::QuicConnection* quicConnection() const override { |
239 | 0 | return initialized_ ? connection() : nullptr; |
240 | 0 | } |
241 | 0 | quic::QuicConnection* quicConnection() override { return initialized_ ? connection() : nullptr; } |
242 | | |
243 | | QuicStatNames quic_stat_names_{stats_store_.symbolTable()}; |
244 | | }; |
245 | | |
246 | | Buffer::OwnedImpl generateChloPacketToSend(quic::ParsedQuicVersion quic_version, |
247 | | quic::QuicConfig& quic_config, |
248 | 0 | quic::QuicConnectionId connection_id) { |
249 | 0 | std::unique_ptr<quic::QuicReceivedPacket> packet = |
250 | 0 | std::move(quic::test::GetFirstFlightOfPackets(quic_version, quic_config, connection_id)[0]); |
251 | 0 | return {packet->data(), packet->length()}; |
252 | 0 | } |
253 | | |
254 | 16.4k | void setQuicConfigWithDefaultValues(quic::QuicConfig* config) { |
255 | 16.4k | quic::test::QuicConfigPeer::SetReceivedMaxBidirectionalStreams( |
256 | 16.4k | config, quic::kDefaultMaxStreamsPerConnection); |
257 | 16.4k | quic::test::QuicConfigPeer::SetReceivedMaxUnidirectionalStreams( |
258 | 16.4k | config, quic::kDefaultMaxStreamsPerConnection); |
259 | 16.4k | quic::test::QuicConfigPeer::SetReceivedInitialMaxStreamDataBytesUnidirectional( |
260 | 16.4k | config, quic::kMinimumFlowControlSendWindow); |
261 | 16.4k | quic::test::QuicConfigPeer::SetReceivedInitialMaxStreamDataBytesIncomingBidirectional( |
262 | 16.4k | config, quic::kMinimumFlowControlSendWindow); |
263 | 16.4k | quic::test::QuicConfigPeer::SetReceivedInitialMaxStreamDataBytesOutgoingBidirectional( |
264 | 16.4k | config, quic::kMinimumFlowControlSendWindow); |
265 | 16.4k | quic::test::QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow( |
266 | 16.4k | config, quic::kMinimumFlowControlSendWindow); |
267 | 16.4k | } |
268 | | |
269 | 0 | std::string spdyHeaderToHttp3StreamPayload(const spdy::Http2HeaderBlock& header) { |
270 | 0 | quic::test::NoopQpackStreamSenderDelegate encoder_stream_sender_delegate; |
271 | 0 | quic::NoopDecoderStreamErrorDelegate decoder_stream_error_delegate; |
272 | 0 | auto qpack_encoder = std::make_unique<quic::QpackEncoder>(&decoder_stream_error_delegate); |
273 | 0 | qpack_encoder->set_qpack_stream_sender_delegate(&encoder_stream_sender_delegate); |
274 | | // QpackEncoder does not use the dynamic table by default, |
275 | | // therefore the value of |stream_id| does not matter. |
276 | 0 | std::string payload = qpack_encoder->EncodeHeaderList(/* stream_id = */ 0, header, nullptr); |
277 | 0 | std::string headers_frame_header = |
278 | 0 | quic::HttpEncoder::SerializeHeadersFrameHeader(payload.length()); |
279 | 0 | return absl::StrCat(headers_frame_header, payload); |
280 | 0 | } |
281 | | |
282 | 0 | std::string bodyToHttp3StreamPayload(const std::string& body) { |
283 | 0 | quiche::SimpleBufferAllocator allocator; |
284 | 0 | quiche::QuicheBuffer header = |
285 | 0 | quic::HttpEncoder::SerializeDataFrameHeader(body.length(), &allocator); |
286 | 0 | return absl::StrCat(header.AsStringView(), body); |
287 | 0 | } |
288 | | |
289 | | // A test suite with variation of ip version and a knob to turn on/off IETF QUIC implementation. |
290 | | class QuicMultiVersionTest : public testing::TestWithParam< |
291 | | std::pair<Network::Address::IpVersion, quic::ParsedQuicVersion>> { |
292 | | }; |
293 | | |
294 | 0 | std::vector<std::pair<Network::Address::IpVersion, quic::ParsedQuicVersion>> generateTestParam() { |
295 | 0 | std::vector<std::pair<Network::Address::IpVersion, quic::ParsedQuicVersion>> param; |
296 | 0 | for (auto ip_version : TestEnvironment::getIpVersionsForTest()) { |
297 | 0 | for (const auto& quic_version : quic::CurrentSupportedHttp3Versions()) { |
298 | 0 | param.emplace_back(ip_version, quic_version); |
299 | 0 | } |
300 | 0 | } |
301 | 0 | return param; |
302 | 0 | } |
303 | | |
304 | | std::string testParamsToString( |
305 | | const ::testing::TestParamInfo<std::pair<Network::Address::IpVersion, quic::ParsedQuicVersion>>& |
306 | 0 | params) { |
307 | 0 | return absl::StrCat(TestUtility::ipVersionToString(params.param.first), |
308 | 0 | quic::QuicVersionToString(params.param.second.transport_version)); |
309 | 0 | } |
310 | | |
311 | | class MockProofVerifyContext : public EnvoyQuicProofVerifyContext { |
312 | | public: |
313 | | MOCK_METHOD(Event::Dispatcher&, dispatcher, (), (const)); |
314 | | MOCK_METHOD(bool, isServer, (), (const)); |
315 | | MOCK_METHOD(const Network::TransportSocketOptionsConstSharedPtr&, transportSocketOptions, (), |
316 | | (const)); |
317 | | MOCK_METHOD(Extensions::TransportSockets::Tls::CertValidator::ExtraValidationContext, |
318 | | extraValidationContext, (), (const)); |
319 | | }; |
320 | | |
321 | | } // namespace Quic |
322 | | } // namespace Envoy |