/proc/self/cwd/test/integration/utility.h
Line | Count | Source (jump to first uncovered line) |
1 | | #pragma once |
2 | | |
3 | | #include <cstdint> |
4 | | #include <functional> |
5 | | #include <memory> |
6 | | #include <string> |
7 | | |
8 | | #include "envoy/api/api.h" |
9 | | #include "envoy/extensions/http/header_validators/envoy_default/v3/header_validator.pb.h" |
10 | | #include "envoy/http/codec.h" |
11 | | #include "envoy/http/header_map.h" |
12 | | #include "envoy/network/filter.h" |
13 | | #include "envoy/server/factory_context.h" |
14 | | #include "envoy/thread_local/thread_local.h" |
15 | | |
16 | | #include "source/common/common/assert.h" |
17 | | #include "source/common/common/dump_state_utils.h" |
18 | | #include "source/common/common/utility.h" |
19 | | #include "source/common/http/codec_client.h" |
20 | | #include "source/common/stats/isolated_store_impl.h" |
21 | | |
22 | | #include "test/test_common/printers.h" |
23 | | #include "test/test_common/test_time.h" |
24 | | #include "test/test_common/utility.h" |
25 | | |
26 | | #include "gtest/gtest.h" |
27 | | |
28 | | namespace Envoy { |
29 | | /** |
30 | | * A buffering response decoder used for testing. |
31 | | */ |
32 | | class BufferingStreamDecoder : public Http::ResponseDecoder, public Http::StreamCallbacks { |
33 | | public: |
34 | 0 | BufferingStreamDecoder(std::function<void()> on_complete_cb) : on_complete_cb_(on_complete_cb) {} Unexecuted instantiation: Envoy::BufferingStreamDecoder::BufferingStreamDecoder(std::__1::function<void ()>) Unexecuted instantiation: Envoy::BufferingStreamDecoder::BufferingStreamDecoder(std::__1::function<void ()>) |
35 | | |
36 | 0 | bool complete() { return complete_; } |
37 | 0 | const Http::ResponseHeaderMap& headers() { return *headers_; } |
38 | 0 | const std::string& body() { return body_; } |
39 | | |
40 | | // Http::StreamDecoder |
41 | | void decodeData(Buffer::Instance&, bool end_stream) override; |
42 | 0 | void decodeMetadata(Http::MetadataMapPtr&&) override {} |
43 | | |
44 | | // Http::ResponseDecoder |
45 | 0 | void decode1xxHeaders(Http::ResponseHeaderMapPtr&&) override {} |
46 | | void decodeHeaders(Http::ResponseHeaderMapPtr&& headers, bool end_stream) override; |
47 | | void decodeTrailers(Http::ResponseTrailerMapPtr&& trailers) override; |
48 | 0 | void dumpState(std::ostream& os, int indent_level) const override { |
49 | 0 | DUMP_STATE_UNIMPLEMENTED(BufferingStreamDecoder); |
50 | 0 | } |
51 | | |
52 | | // Http::StreamCallbacks |
53 | | void onResetStream(Http::StreamResetReason reason, |
54 | | absl::string_view transport_failure_reason) override; |
55 | 0 | void onAboveWriteBufferHighWatermark() override {} |
56 | 0 | void onBelowWriteBufferLowWatermark() override {} |
57 | | |
58 | | private: |
59 | | void onComplete(); |
60 | | |
61 | | Http::ResponseHeaderMapPtr headers_; |
62 | | std::string body_; |
63 | | bool complete_{}; |
64 | | std::function<void()> on_complete_cb_; |
65 | | }; |
66 | | |
67 | | using BufferingStreamDecoderPtr = std::unique_ptr<BufferingStreamDecoder>; |
68 | | |
69 | | /** |
70 | | * Basic driver for a raw connection. |
71 | | */ |
72 | | class RawConnectionDriver { |
73 | | public: |
74 | | // Callback that is executed to write data to connection. The provided buffer |
75 | | // should be populated with the data to write. If the callback returns true, |
76 | | // the connection will be closed after writing. |
77 | | using DoWriteCallback = std::function<bool(Buffer::Instance&)>; |
78 | | using ReadCallback = std::function<void(Network::ClientConnection&, const Buffer::Instance&)>; |
79 | | |
80 | | RawConnectionDriver(uint32_t port, DoWriteCallback write_request_callback, |
81 | | ReadCallback response_data_callback, Network::Address::IpVersion version, |
82 | | Event::Dispatcher& dispatcher, |
83 | | Network::TransportSocketPtr transport_socket = nullptr); |
84 | | // Similar to the constructor above but accepts the request as a constructor argument. |
85 | | RawConnectionDriver(uint32_t port, Buffer::Instance& request_data, |
86 | | ReadCallback response_data_callback, Network::Address::IpVersion version, |
87 | | Event::Dispatcher& dispatcher, |
88 | | Network::TransportSocketPtr transport_socket = nullptr); |
89 | | ~RawConnectionDriver(); |
90 | | |
91 | | testing::AssertionResult |
92 | | run(Event::Dispatcher::RunType run_type = Event::Dispatcher::RunType::Block, |
93 | | std::chrono::milliseconds timeout = TestUtility::DefaultTimeout); |
94 | | void close(); |
95 | 0 | Network::ConnectionEvent lastConnectionEvent() const { |
96 | 0 | return callbacks_->last_connection_event_; |
97 | 0 | } |
98 | | // Wait until connected or closed(). |
99 | | ABSL_MUST_USE_RESULT testing::AssertionResult waitForConnection(); |
100 | | |
101 | 0 | bool closed() { return callbacks_->closed(); } |
102 | | bool allBytesSent() const; |
103 | | |
104 | | private: |
105 | | struct ForwardingFilter : public Network::ReadFilterBaseImpl { |
106 | | ForwardingFilter(RawConnectionDriver& parent, ReadCallback cb) |
107 | 0 | : parent_(parent), response_data_callback_(cb) {} |
108 | | |
109 | | // Network::ReadFilter |
110 | 0 | Network::FilterStatus onData(Buffer::Instance& data, bool) override { |
111 | 0 | response_data_callback_(*parent_.client_, data); |
112 | 0 | data.drain(data.length()); |
113 | 0 | return Network::FilterStatus::StopIteration; |
114 | 0 | } |
115 | | |
116 | | RawConnectionDriver& parent_; |
117 | | ReadCallback response_data_callback_; |
118 | | }; |
119 | | |
120 | | struct ConnectionCallbacks : public Network::ConnectionCallbacks { |
121 | | using WriteCb = std::function<void()>; |
122 | | |
123 | | ConnectionCallbacks(WriteCb write_cb, Event::Dispatcher& dispatcher) |
124 | 0 | : write_cb_(write_cb), dispatcher_(dispatcher) {} |
125 | 0 | bool connected() const { return connected_; } |
126 | 0 | bool closed() const { return closed_; } |
127 | | |
128 | | // Network::ConnectionCallbacks |
129 | 0 | void onEvent(Network::ConnectionEvent event) override { |
130 | 0 | if (!connected_ && event == Network::ConnectionEvent::Connected) { |
131 | 0 | write_cb_(); |
132 | 0 | } |
133 | 0 | last_connection_event_ = event; |
134 | |
|
135 | 0 | closed_ |= (event == Network::ConnectionEvent::RemoteClose || |
136 | 0 | event == Network::ConnectionEvent::LocalClose); |
137 | 0 | connected_ |= (event == Network::ConnectionEvent::Connected); |
138 | |
|
139 | 0 | if (closed_) { |
140 | 0 | dispatcher_.exit(); |
141 | 0 | } |
142 | 0 | } |
143 | 0 | void onAboveWriteBufferHighWatermark() override {} |
144 | 0 | void onBelowWriteBufferLowWatermark() override { write_cb_(); } |
145 | | |
146 | | Network::ConnectionEvent last_connection_event_; |
147 | | |
148 | | private: |
149 | | WriteCb write_cb_; |
150 | | Event::Dispatcher& dispatcher_; |
151 | | bool connected_{false}; |
152 | | bool closed_{false}; |
153 | | }; |
154 | | |
155 | | Stats::IsolatedStoreImpl stats_store_; |
156 | | Api::ApiPtr api_; |
157 | | Event::Dispatcher& dispatcher_; |
158 | | std::unique_ptr<ConnectionCallbacks> callbacks_; |
159 | | Network::ClientConnectionPtr client_; |
160 | | uint64_t remaining_bytes_to_send_; |
161 | | }; |
162 | | |
163 | | /** |
164 | | * Utility routines for integration tests. |
165 | | */ |
166 | | class IntegrationUtil { |
167 | | public: |
168 | | /** |
169 | | * Make a new connection, issues a request, and then disconnect when the request is complete. |
170 | | * @param addr supplies the address to connect to. |
171 | | * @param method supplies the request method. |
172 | | * @param url supplies the request url. |
173 | | * @param body supplies the optional request body to send. |
174 | | * @param type supplies the codec to use for the request. |
175 | | * @param host supplies the host header to use for the request. |
176 | | * @param content_type supplies the content-type header to use for the request, if any. |
177 | | * @return BufferingStreamDecoderPtr the complete request or a partial request if there was |
178 | | * remote early disconnection. |
179 | | */ |
180 | | static BufferingStreamDecoderPtr |
181 | | makeSingleRequest(const Network::Address::InstanceConstSharedPtr& addr, const std::string& method, |
182 | | const std::string& url, const std::string& body, Http::CodecType type, |
183 | | const std::string& host = "host", const std::string& content_type = ""); |
184 | | |
185 | | /** |
186 | | * Make a new connection, issues a request, and then disconnect when the request is complete. |
187 | | * @param port supplies the port to connect to on localhost. |
188 | | * @param method supplies the request method. |
189 | | * @param url supplies the request url. |
190 | | * @param body supplies the optional request body to send. |
191 | | * @param type supplies the codec to use for the request. |
192 | | * @param version the IP address version of the client and server. |
193 | | * @param host supplies the host header to use for the request. |
194 | | * @param content_type supplies the content-type header to use for the request, if any. |
195 | | * @return BufferingStreamDecoderPtr the complete request or a partial request if there was |
196 | | * remote early disconnection. |
197 | | */ |
198 | | static BufferingStreamDecoderPtr makeSingleRequest(uint32_t port, const std::string& method, |
199 | | const std::string& url, |
200 | | const std::string& body, Http::CodecType type, |
201 | | Network::Address::IpVersion ip_version, |
202 | | const std::string& host = "host", |
203 | | const std::string& content_type = ""); |
204 | | |
205 | | /** |
206 | | * Create transport socket factory for Quic upstream transport socket. |
207 | | * @return TransportSocketFactoryPtr the client transport socket factory. |
208 | | */ |
209 | | static Network::UpstreamTransportSocketFactoryPtr createQuicUpstreamTransportSocketFactory( |
210 | | Api::Api& api, Stats::Store& store, Ssl::ContextManager& context_manager, |
211 | | ThreadLocal::Instance& threadlocal, const std::string& san_to_match, |
212 | | // Allow configuring TLS to talk to upstreams instead of Envoy |
213 | | bool connect_to_fake_upstreams = false); |
214 | | |
215 | | static Http::HeaderValidatorFactoryPtr makeHeaderValidationFactory( |
216 | | const ::envoy::extensions::http::header_validators::envoy_default::v3::HeaderValidatorConfig& |
217 | | config); |
218 | | }; |
219 | | |
220 | | // A set of connection callbacks which tracks connection state. |
221 | | class ConnectionStatusCallbacks : public Network::ConnectionCallbacks { |
222 | | public: |
223 | 0 | bool connected() const { return connected_; } |
224 | 0 | bool closed() const { return closed_; } |
225 | 0 | void reset() { |
226 | 0 | connected_ = false; |
227 | 0 | closed_ = false; |
228 | 0 | } |
229 | | |
230 | | // Network::ConnectionCallbacks |
231 | 0 | void onEvent(Network::ConnectionEvent event) override { |
232 | 0 | closed_ |= (event == Network::ConnectionEvent::RemoteClose || |
233 | 0 | event == Network::ConnectionEvent::LocalClose); |
234 | 0 | connected_ |= (event == Network::ConnectionEvent::Connected); |
235 | 0 | } |
236 | 0 | void onAboveWriteBufferHighWatermark() override {} |
237 | 0 | void onBelowWriteBufferLowWatermark() override {} |
238 | | |
239 | | private: |
240 | | bool connected_{false}; |
241 | | bool closed_{false}; |
242 | | }; |
243 | | |
244 | | // A read filter which waits for a given data then stops the dispatcher loop. |
245 | | class WaitForPayloadReader : public Network::ReadFilterBaseImpl { |
246 | | public: |
247 | | WaitForPayloadReader(Event::Dispatcher& dispatcher); |
248 | | |
249 | | // Network::ReadFilter |
250 | | Network::FilterStatus onData(Buffer::Instance& data, bool end_stream) override; |
251 | | |
252 | 0 | void setDataToWaitFor(const std::string& data, bool exact_match = true) { |
253 | 0 | data_to_wait_for_ = data; |
254 | 0 | exact_match_ = exact_match; |
255 | 0 | } |
256 | | |
257 | | ABSL_MUST_USE_RESULT testing::AssertionResult waitForLength(size_t length, |
258 | 0 | std::chrono::milliseconds timeout) { |
259 | 0 | ASSERT(!wait_for_length_); |
260 | 0 | length_to_wait_for_ = length; |
261 | 0 | wait_for_length_ = true; |
262 | |
|
263 | 0 | Event::TimerPtr timeout_timer = |
264 | 0 | dispatcher_.createTimer([this]() -> void { dispatcher_.exit(); }); |
265 | 0 | timeout_timer->enableTimer(timeout); |
266 | |
|
267 | 0 | dispatcher_.run(Event::Dispatcher::RunType::Block); |
268 | |
|
269 | 0 | if (timeout_timer->enabled()) { |
270 | 0 | timeout_timer->disableTimer(); |
271 | 0 | return testing::AssertionSuccess(); |
272 | 0 | } |
273 | | |
274 | 0 | length_to_wait_for_ = 0; |
275 | 0 | wait_for_length_ = false; |
276 | 0 | return testing::AssertionFailure() << "Timed out waiting for " << length << " bytes of data\n"; |
277 | 0 | } |
278 | | |
279 | 0 | const std::string& data() { return data_; } |
280 | 0 | bool readLastByte() { return read_end_stream_; } |
281 | 0 | void clearData(size_t count = std::string::npos) { data_.erase(0, count); } |
282 | | |
283 | | private: |
284 | | Event::Dispatcher& dispatcher_; |
285 | | std::string data_to_wait_for_; |
286 | | std::string data_; |
287 | | bool exact_match_{true}; |
288 | | bool read_end_stream_{}; |
289 | | size_t length_to_wait_for_{0}; |
290 | | bool wait_for_length_{false}; |
291 | | }; |
292 | | |
293 | | } // namespace Envoy |