forked from envoyproxy/envoy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
utility.h
239 lines (198 loc) · 8.41 KB
/
utility.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
#pragma once
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
#include "envoy/api/api.h"
#include "envoy/http/codec.h"
#include "envoy/http/header_map.h"
#include "envoy/network/filter.h"
#include "common/common/assert.h"
#include "common/common/utility.h"
#include "common/http/codec_client.h"
#include "common/stats/isolated_store_impl.h"
#include "test/test_common/printers.h"
#include "test/test_common/test_time.h"
#include "gtest/gtest.h"
namespace Envoy {
/**
* A buffering response decoder used for testing.
*/
class BufferingStreamDecoder : public Http::ResponseDecoder, public Http::StreamCallbacks {
public:
BufferingStreamDecoder(std::function<void()> on_complete_cb) : on_complete_cb_(on_complete_cb) {}
bool complete() { return complete_; }
const Http::ResponseHeaderMap& headers() { return *headers_; }
const std::string& body() { return body_; }
// Http::StreamDecoder
void decodeData(Buffer::Instance&, bool end_stream) override;
void decodeMetadata(Http::MetadataMapPtr&&) override {}
// Http::ResponseDecoder
void decode100ContinueHeaders(Http::ResponseHeaderMapPtr&&) override {}
void decodeHeaders(Http::ResponseHeaderMapPtr&& headers, bool end_stream) override;
void decodeTrailers(Http::ResponseTrailerMapPtr&& trailers) override;
// Http::StreamCallbacks
void onResetStream(Http::StreamResetReason reason,
absl::string_view transport_failure_reason) override;
void onAboveWriteBufferHighWatermark() override {}
void onBelowWriteBufferLowWatermark() override {}
private:
void onComplete();
Http::ResponseHeaderMapPtr headers_;
std::string body_;
bool complete_{};
std::function<void()> on_complete_cb_;
};
using BufferingStreamDecoderPtr = std::unique_ptr<BufferingStreamDecoder>;
/**
* Basic driver for a raw connection.
*/
class RawConnectionDriver {
public:
using ReadCallback = std::function<void(Network::ClientConnection&, const Buffer::Instance&)>;
RawConnectionDriver(uint32_t port, Buffer::Instance& initial_data, ReadCallback data_callback,
Network::Address::IpVersion version, Event::Dispatcher& dispatcher,
Network::TransportSocketPtr transport_socket = nullptr);
~RawConnectionDriver();
const Network::Connection& connection() { return *client_; }
void run(Event::Dispatcher::RunType run_type = Event::Dispatcher::RunType::Block);
void close();
Network::ConnectionEvent lastConnectionEvent() const {
return callbacks_->last_connection_event_;
}
// Wait until connected or closed().
void waitForConnection();
bool closed() { return callbacks_->closed(); }
private:
struct ForwardingFilter : public Network::ReadFilterBaseImpl {
ForwardingFilter(RawConnectionDriver& parent, ReadCallback cb)
: parent_(parent), data_callback_(cb) {}
// Network::ReadFilter
Network::FilterStatus onData(Buffer::Instance& data, bool) override {
data_callback_(*parent_.client_, data);
data.drain(data.length());
return Network::FilterStatus::StopIteration;
}
RawConnectionDriver& parent_;
ReadCallback data_callback_;
};
struct ConnectionCallbacks : public Network::ConnectionCallbacks {
bool connected() const { return connected_; }
bool closed() const { return closed_; }
// Network::ConnectionCallbacks
void onEvent(Network::ConnectionEvent event) override {
last_connection_event_ = event;
closed_ |= (event == Network::ConnectionEvent::RemoteClose ||
event == Network::ConnectionEvent::LocalClose);
connected_ |= (event == Network::ConnectionEvent::Connected);
}
void onAboveWriteBufferHighWatermark() override {}
void onBelowWriteBufferLowWatermark() override {}
Network::ConnectionEvent last_connection_event_;
private:
bool connected_{false};
bool closed_{false};
};
Stats::IsolatedStoreImpl stats_store_;
Api::ApiPtr api_;
Event::Dispatcher& dispatcher_;
std::unique_ptr<ConnectionCallbacks> callbacks_;
Network::ClientConnectionPtr client_;
};
/**
* Utility routines for integration tests.
*/
class IntegrationUtil {
public:
/**
* Make a new connection, issues a request, and then disconnect when the request is complete.
* @param addr supplies the address to connect to.
* @param method supplies the request method.
* @param url supplies the request url.
* @param body supplies the optional request body to send.
* @param type supplies the codec to use for the request.
* @param host supplies the host header to use for the request.
* @param content_type supplies the content-type header to use for the request, if any.
* @return BufferingStreamDecoderPtr the complete request or a partial request if there was
* remote early disconnection.
*/
static BufferingStreamDecoderPtr
makeSingleRequest(const Network::Address::InstanceConstSharedPtr& addr, const std::string& method,
const std::string& url, const std::string& body, Http::CodecClient::Type type,
const std::string& host = "host", const std::string& content_type = "");
/**
* Make a new connection, issues a request, and then disconnect when the request is complete.
* @param port supplies the port to connect to on localhost.
* @param method supplies the request method.
* @param url supplies the request url.
* @param body supplies the optional request body to send.
* @param type supplies the codec to use for the request.
* @param version the IP address version of the client and server.
* @param host supplies the host header to use for the request.
* @param content_type supplies the content-type header to use for the request, if any.
* @return BufferingStreamDecoderPtr the complete request or a partial request if there was
* remote early disconnection.
*/
static BufferingStreamDecoderPtr
makeSingleRequest(uint32_t port, const std::string& method, const std::string& url,
const std::string& body, Http::CodecClient::Type type,
Network::Address::IpVersion ip_version, const std::string& host = "host",
const std::string& content_type = "");
};
// A set of connection callbacks which tracks connection state.
class ConnectionStatusCallbacks : public Network::ConnectionCallbacks {
public:
bool connected() const { return connected_; }
bool closed() const { return closed_; }
// Network::ConnectionCallbacks
void onEvent(Network::ConnectionEvent event) override {
closed_ |= (event == Network::ConnectionEvent::RemoteClose ||
event == Network::ConnectionEvent::LocalClose);
connected_ |= (event == Network::ConnectionEvent::Connected);
}
void onAboveWriteBufferHighWatermark() override {}
void onBelowWriteBufferLowWatermark() override {}
private:
bool connected_{false};
bool closed_{false};
};
// A read filter which waits for a given data then stops the dispatcher loop.
class WaitForPayloadReader : public Network::ReadFilterBaseImpl {
public:
WaitForPayloadReader(Event::Dispatcher& dispatcher);
// Network::ReadFilter
Network::FilterStatus onData(Buffer::Instance& data, bool end_stream) override;
void set_data_to_wait_for(const std::string& data, bool exact_match = true) {
data_to_wait_for_ = data;
exact_match_ = exact_match;
}
ABSL_MUST_USE_RESULT testing::AssertionResult waitForLength(size_t length,
std::chrono::milliseconds timeout) {
ASSERT(!wait_for_length_);
length_to_wait_for_ = length;
wait_for_length_ = true;
Event::TimerPtr timeout_timer =
dispatcher_.createTimer([this]() -> void { dispatcher_.exit(); });
timeout_timer->enableTimer(timeout);
dispatcher_.run(Event::Dispatcher::RunType::Block);
if (timeout_timer->enabled()) {
timeout_timer->disableTimer();
return testing::AssertionSuccess();
}
length_to_wait_for_ = 0;
wait_for_length_ = false;
return testing::AssertionFailure() << "Timed out waiting for " << length << " bytes of data\n";
}
const std::string& data() { return data_; }
bool readLastByte() { return read_end_stream_; }
void clearData(size_t count = std::string::npos) { data_.erase(0, count); }
private:
Event::Dispatcher& dispatcher_;
std::string data_to_wait_for_;
std::string data_;
bool exact_match_{true};
bool read_end_stream_{};
size_t length_to_wait_for_{0};
bool wait_for_length_{false};
};
} // namespace Envoy