@@ -75,6 +75,106 @@ TEST_P(DrainCloseIntegrationTest, DrainCloseImmediate) {
75
75
76
76
TEST_P (DrainCloseIntegrationTest, AdminDrain) { testAdminDrain (downstreamProtocol ()); }
77
77
78
+ TEST_P (DrainCloseIntegrationTest, AdminGracefulDrain) {
79
+ drain_strategy_ = Server::DrainStrategy::Immediate;
80
+ drain_time_ = std::chrono::seconds (999 );
81
+ initialize ();
82
+ fake_upstreams_[0 ]->set_allow_unexpected_disconnects (true );
83
+ uint32_t http_port = lookupPort (" http" );
84
+ codec_client_ = makeHttpConnection (http_port);
85
+
86
+ auto response = codec_client_->makeHeaderOnlyRequest (default_request_headers_);
87
+ waitForNextUpstreamRequest (0 );
88
+ upstream_request_->encodeHeaders (default_response_headers_, true );
89
+ response->waitForEndStream ();
90
+ ASSERT_TRUE (response->complete ());
91
+ EXPECT_THAT (response->headers (), Http::HttpStatusIs (" 200" ));
92
+ // The request is completed but the connection remains open.
93
+ EXPECT_TRUE (codec_client_->connected ());
94
+
95
+ // Invoke /drain_listeners with graceful drain
96
+ BufferingStreamDecoderPtr admin_response = IntegrationUtil::makeSingleRequest (
97
+ lookupPort (" admin" ), " POST" , " /drain_listeners?graceful" , " " , downstreamProtocol (), version_);
98
+ EXPECT_EQ (admin_response->headers ().Status ()->value ().getStringView (), " 200" );
99
+
100
+ // With a 999s graceful drain period, the listener should still be open.
101
+ EXPECT_EQ (test_server_->counter (" listener_manager.listener_stopped" )->value (), 0 );
102
+
103
+ response = codec_client_->makeHeaderOnlyRequest (default_request_headers_);
104
+ waitForNextUpstreamRequest (0 );
105
+ upstream_request_->encodeHeaders (default_response_headers_, true );
106
+ response->waitForEndStream ();
107
+ ASSERT_TRUE (response->complete ());
108
+ EXPECT_THAT (response->headers (), Http::HttpStatusIs (" 200" ));
109
+
110
+ // Connections will terminate on request complete
111
+ ASSERT_TRUE (codec_client_->waitForDisconnect ());
112
+ if (downstream_protocol_ == Http::CodecClient::Type::HTTP2) {
113
+ EXPECT_TRUE (codec_client_->sawGoAway ());
114
+ } else {
115
+ EXPECT_EQ (" close" , response->headers ().getConnectionValue ());
116
+ }
117
+
118
+ // New connections can still be made.
119
+ auto second_codec_client_ = makeRawHttpConnection (makeClientConnection (http_port));
120
+ EXPECT_TRUE (second_codec_client_->connected ());
121
+
122
+ // Invoke /drain_listeners and shut down listeners.
123
+ second_codec_client_->rawConnection ().close (Network::ConnectionCloseType::NoFlush);
124
+ admin_response = IntegrationUtil::makeSingleRequest (
125
+ lookupPort (" admin" ), " POST" , " /drain_listeners" , " " , downstreamProtocol (), version_);
126
+ EXPECT_EQ (admin_response->headers ().Status ()->value ().getStringView (), " 200" );
127
+
128
+ test_server_->waitForCounterEq (" listener_manager.listener_stopped" , 1 );
129
+ EXPECT_NO_THROW (Network::TcpListenSocket (
130
+ Network::Utility::getAddressWithPort (*Network::Test::getCanonicalLoopbackAddress (version_),
131
+ http_port),
132
+ nullptr , true ));
133
+ }
134
+
135
+ TEST_P (DrainCloseIntegrationTest, RepeatedAdminGracefulDrain) {
136
+ // Use the default gradual probabilistic DrainStrategy so drainClose()
137
+ // behaviour isn't conflated with whether the drain sequence has started.
138
+ drain_time_ = std::chrono::seconds (999 );
139
+ initialize ();
140
+ fake_upstreams_[0 ]->set_allow_unexpected_disconnects (true );
141
+ uint32_t http_port = lookupPort (" http" );
142
+ codec_client_ = makeHttpConnection (http_port);
143
+
144
+ auto response = codec_client_->makeHeaderOnlyRequest (default_request_headers_);
145
+ waitForNextUpstreamRequest (0 );
146
+ upstream_request_->encodeHeaders (default_response_headers_, true );
147
+ response->waitForEndStream ();
148
+
149
+ // Invoke /drain_listeners with graceful drain
150
+ BufferingStreamDecoderPtr admin_response = IntegrationUtil::makeSingleRequest (
151
+ lookupPort (" admin" ), " POST" , " /drain_listeners?graceful" , " " , downstreamProtocol (), version_);
152
+ EXPECT_EQ (admin_response->headers ().Status ()->value ().getStringView (), " 200" );
153
+ EXPECT_EQ (test_server_->counter (" listener_manager.listener_stopped" )->value (), 0 );
154
+
155
+ admin_response = IntegrationUtil::makeSingleRequest (
156
+ lookupPort (" admin" ), " POST" , " /drain_listeners?graceful" , " " , downstreamProtocol (), version_);
157
+ EXPECT_EQ (admin_response->headers ().Status ()->value ().getStringView (), " 200" );
158
+ EXPECT_EQ (admin_response->headers ().Status ()->value ().getStringView (), " 200" );
159
+
160
+ response = codec_client_->makeHeaderOnlyRequest (default_request_headers_);
161
+ waitForNextUpstreamRequest (0 );
162
+ upstream_request_->encodeHeaders (default_response_headers_, true );
163
+ response->waitForEndStream ();
164
+ ASSERT_TRUE (response->complete ());
165
+ EXPECT_THAT (response->headers (), Http::HttpStatusIs (" 200" ));
166
+
167
+ admin_response = IntegrationUtil::makeSingleRequest (
168
+ lookupPort (" admin" ), " POST" , " /drain_listeners" , " " , downstreamProtocol (), version_);
169
+ EXPECT_EQ (admin_response->headers ().Status ()->value ().getStringView (), " 200" );
170
+
171
+ test_server_->waitForCounterEq (" listener_manager.listener_stopped" , 1 );
172
+ EXPECT_NO_THROW (Network::TcpListenSocket (
173
+ Network::Utility::getAddressWithPort (*Network::Test::getCanonicalLoopbackAddress (version_),
174
+ http_port),
175
+ nullptr , true ));
176
+ }
177
+
78
178
INSTANTIATE_TEST_SUITE_P (Protocols, DrainCloseIntegrationTest,
79
179
testing::ValuesIn (HttpProtocolIntegrationTest::getProtocolTestParams(
80
180
{Http::CodecClient::Type::HTTP1, Http::CodecClient::Type::HTTP2},
0 commit comments