Coverage Report

Created: 2024-09-19 09:45

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