forked from envoyproxy/envoy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
echo_integration_test.cc
149 lines (132 loc) · 4.94 KB
/
echo_integration_test.cc
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
#include "test/integration/integration.h"
#include "test/integration/utility.h"
#include "test/server/utility.h"
#include "test/test_common/utility.h"
namespace Envoy {
std::string echo_config;
class EchoIntegrationTest : public BaseIntegrationTest,
public testing::TestWithParam<Network::Address::IpVersion> {
public:
EchoIntegrationTest() : BaseIntegrationTest(GetParam(), realTime(), echo_config) {}
// Called once by the gtest framework before any EchoIntegrationTests are run.
static void SetUpTestCase() {
echo_config = ConfigHelper::BASE_CONFIG + R"EOF(
filter_chains:
filters:
name: envoy.ratelimit
config:
domain: foo
stats_prefix: name
descriptors: [{"key": "foo", "value": "bar"}]
filters:
name: envoy.echo
config:
)EOF";
}
/**
* Initializer for an individual test.
*/
void SetUp() override { BaseIntegrationTest::initialize(); }
/**
* Destructor for an individual test.
*/
void TearDown() override {
test_server_.reset();
fake_upstreams_.clear();
}
};
INSTANTIATE_TEST_CASE_P(IpVersions, EchoIntegrationTest,
testing::ValuesIn(TestEnvironment::getIpVersionsForTest()),
TestUtility::ipTestParamsToString);
TEST_P(EchoIntegrationTest, Hello) {
Buffer::OwnedImpl buffer("hello");
std::string response;
RawConnectionDriver connection(
lookupPort("listener_0"), buffer,
[&](Network::ClientConnection&, const Buffer::Instance& data) -> void {
response.append(data.toString());
connection.close();
},
version_);
connection.run();
EXPECT_EQ("hello", response);
}
TEST_P(EchoIntegrationTest, AddRemoveListener) {
const std::string json = TestEnvironment::substitute(R"EOF(
{
"name": "new_listener",
"address": "tcp://{{ ip_loopback_address }}:0",
"filters": [
{ "name": "echo", "config": {} }
]
}
)EOF",
GetParam());
// Add the listener.
ConditionalInitializer listener_added_by_worker;
ConditionalInitializer listener_added_by_manager;
test_server_->setOnWorkerListenerAddedCb(
[&listener_added_by_worker]() -> void { listener_added_by_worker.setReady(); });
test_server_->server().dispatcher().post([this, json, &listener_added_by_manager]() -> void {
EXPECT_TRUE(test_server_->server().listenerManager().addOrUpdateListener(
Server::parseListenerFromJson(json), "", true));
listener_added_by_manager.setReady();
});
listener_added_by_worker.waitReady();
listener_added_by_manager.waitReady();
EXPECT_EQ(2UL, test_server_->server().listenerManager().listeners().size());
uint32_t new_listener_port = test_server_->server()
.listenerManager()
.listeners()[1]
.get()
.socket()
.localAddress()
->ip()
->port();
Buffer::OwnedImpl buffer("hello");
std::string response;
RawConnectionDriver connection(
new_listener_port, buffer,
[&](Network::ClientConnection&, const Buffer::Instance& data) -> void {
response.append(data.toString());
connection.close();
},
version_);
connection.run();
EXPECT_EQ("hello", response);
// Remove the listener.
ConditionalInitializer listener_removed;
test_server_->setOnWorkerListenerRemovedCb(
[&listener_removed]() -> void { listener_removed.setReady(); });
test_server_->server().dispatcher().post([this]() -> void {
EXPECT_TRUE(test_server_->server().listenerManager().removeListener("new_listener"));
});
listener_removed.waitReady();
// Now connect. This should fail.
// Allow for a few attempts, in order to handle a race (likely due to lack of
// LEV_OPT_CLOSE_ON_FREE, which would break listener reuse)
//
// In order for this test to work, it must be tagged as "exclusive" in its
// build file. Otherwise, it's possible that when the listener is destroyed
// above, another test would start listening on the released port, and this
// connect would unexpectedly succeed.
bool connect_fail = false;
for (int i = 0; i < 10; ++i) {
RawConnectionDriver connection2(
new_listener_port, buffer,
[&](Network::ClientConnection&, const Buffer::Instance&) -> void { FAIL(); }, version_);
while (connection2.connecting()) {
// Don't busy loop, but OS X often needs a moment to decide this connection isn't happening.
timeSystem().sleep(std::chrono::milliseconds(10));
connection2.run(Event::Dispatcher::RunType::NonBlock);
}
if (connection2.connection().state() == Network::Connection::State::Closed) {
connect_fail = true;
break;
} else {
connection2.close();
}
}
ASSERT_TRUE(connect_fail);
}
} // namespace Envoy