Coverage Report

Created: 2023-11-12 09:30

/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