TensorFlow Serving C++ API Documentation
evhttp_server_test.cc
1 /* Copyright 2018 Google Inc. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7  http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 #include "tensorflow_serving/util/net_http/server/internal/evhttp_server.h"
17 
18 #include <functional>
19 #include <memory>
20 #include <utility>
21 
22 #include <gtest/gtest.h>
23 #include "absl/memory/memory.h"
24 #include "absl/synchronization/notification.h"
25 #include "tensorflow_serving/util/net_http/client/test_client/internal/evhttp_connection.h"
26 #include "tensorflow_serving/util/net_http/internal/fixed_thread_pool.h"
27 #include "tensorflow_serving/util/net_http/server/public/httpserver.h"
28 #include "tensorflow_serving/util/net_http/server/public/httpserver_interface.h"
29 #include "tensorflow_serving/util/net_http/server/public/server_request_interface.h"
30 
31 namespace tensorflow {
32 namespace serving {
33 namespace net_http {
34 namespace {
35 
36 class MyExecutor final : public EventExecutor {
37  public:
38  explicit MyExecutor(int num_threads) : thread_pool_(num_threads) {}
39 
40  void Schedule(std::function<void()> fn) override {
41  thread_pool_.Schedule(fn);
42  }
43 
44  private:
45  FixedThreadPool thread_pool_;
46 };
47 
48 class EvHTTPServerTest : public ::testing::Test {
49  public:
50  void SetUp() override { InitServer(); }
51 
52  void TearDown() override {
53  if (!server->is_terminating()) {
54  server->Terminate();
55  server->WaitForTermination();
56  }
57  }
58 
59  protected:
60  std::unique_ptr<HTTPServerInterface> server;
61 
62  private:
63  void InitServer() {
64  auto options = absl::make_unique<ServerOptions>();
65  options->AddPort(0);
66  options->SetExecutor(absl::make_unique<MyExecutor>(4));
67 
68  server = CreateEvHTTPServer(std::move(options));
69 
70  ASSERT_TRUE(server != nullptr);
71  }
72 };
73 
74 // Test StartAcceptingRequests
75 TEST_F(EvHTTPServerTest, AcceptingTerminating) {
76  EXPECT_FALSE(server->is_accepting_requests());
77  server->StartAcceptingRequests();
78  EXPECT_TRUE(server->is_accepting_requests());
79 
80  server->Terminate();
81  EXPECT_TRUE(server->is_terminating());
82 
83  server->WaitForTermination();
84 }
85 
86 // Test the path matching behavior
87 TEST_F(EvHTTPServerTest, ExactPathMatching) {
88  auto handler = [](ServerRequestInterface* request) {
89  request->WriteResponseString("OK");
90  request->Reply();
91  };
92  server->RegisterRequestHandler("/ok", std::move(handler),
93  RequestHandlerOptions());
94  server->StartAcceptingRequests();
95 
96  auto connection =
97  TestEvHTTPConnection::Connect("localhost", server->listen_port());
98  ASSERT_TRUE(connection != nullptr);
99 
100  TestClientRequest request = {"/ok?a=foo", "GET", {}, ""};
101  TestClientResponse response = {};
102 
103  EXPECT_TRUE(connection->BlockingSendRequest(request, &response));
104  EXPECT_EQ(response.status, HTTPStatusCode::OK);
105  EXPECT_EQ(response.body, "OK");
106 
107  // no canonicalization for the trailing "/"
108  request = {"/ok/", "GET", {}, ""};
109  response = {};
110 
111  EXPECT_TRUE(connection->BlockingSendRequest(request, &response));
112  EXPECT_EQ(response.status, HTTPStatusCode::NOT_FOUND);
113 
114  server->Terminate();
115  server->WaitForTermination();
116 }
117 
118 // Test RequestHandler overwriting
119 TEST_F(EvHTTPServerTest, RequestHandlerOverwriting) {
120  auto handler1 = [](ServerRequestInterface* request) {
121  request->WriteResponseString("OK1");
122  request->Reply();
123  };
124  auto handler2 = [](ServerRequestInterface* request) {
125  request->WriteResponseString("OK2");
126  request->Reply();
127  };
128 
129  server->RegisterRequestHandler("/ok", std::move(handler1),
130  RequestHandlerOptions());
131  server->RegisterRequestHandler("/ok", std::move(handler2),
132  RequestHandlerOptions());
133  server->StartAcceptingRequests();
134 
135  auto connection =
136  TestEvHTTPConnection::Connect("localhost", server->listen_port());
137  ASSERT_TRUE(connection != nullptr);
138 
139  TestClientRequest request = {"/ok", "GET", {}, ""};
140  TestClientResponse response = {};
141 
142  EXPECT_TRUE(connection->BlockingSendRequest(request, &response));
143  EXPECT_EQ(response.status, HTTPStatusCode::OK);
144  EXPECT_EQ(response.body, "OK2");
145 
146  server->Terminate();
147  server->WaitForTermination();
148 }
149 
150 // Test single RequestDispatcher
151 TEST_F(EvHTTPServerTest, SingleRequestDispather) {
152  auto handler = [](ServerRequestInterface* request) {
153  request->WriteResponseString("OK");
154  request->Reply();
155  };
156 
157  auto dispatcher = [&handler](ServerRequestInterface* request) {
158  return handler;
159  };
160 
161  server->RegisterRequestDispatcher(std::move(dispatcher),
162  RequestHandlerOptions());
163  server->StartAcceptingRequests();
164 
165  auto connection =
166  TestEvHTTPConnection::Connect("localhost", server->listen_port());
167  ASSERT_TRUE(connection != nullptr);
168 
169  TestClientRequest request = {"/ok", "GET", {}, ""};
170  TestClientResponse response = {};
171 
172  EXPECT_TRUE(connection->BlockingSendRequest(request, &response));
173  EXPECT_EQ(response.status, HTTPStatusCode::OK);
174  EXPECT_EQ(response.body, "OK");
175 
176  server->Terminate();
177  server->WaitForTermination();
178 }
179 
180 // Test URI path precedes over RequestDispatcher
181 TEST_F(EvHTTPServerTest, UriPrecedesOverRequestDispather) {
182  auto handler1 = [](ServerRequestInterface* request) {
183  request->WriteResponseString("OK1");
184  request->Reply();
185  };
186 
187  server->RegisterRequestHandler("/ok", std::move(handler1),
188  RequestHandlerOptions());
189 
190  auto handler2 = [](ServerRequestInterface* request) {
191  request->WriteResponseString("OK2");
192  request->Reply();
193  };
194 
195  auto dispatcher = [&handler2](ServerRequestInterface* request) {
196  return handler2;
197  };
198  server->RegisterRequestDispatcher(std::move(dispatcher),
199  RequestHandlerOptions());
200 
201  server->StartAcceptingRequests();
202 
203  auto connection =
204  TestEvHTTPConnection::Connect("localhost", server->listen_port());
205  ASSERT_TRUE(connection != nullptr);
206 
207  TestClientRequest request = {"/ok", "GET", {}, ""};
208  TestClientResponse response = {};
209 
210  EXPECT_TRUE(connection->BlockingSendRequest(request, &response));
211  EXPECT_EQ(response.status, HTTPStatusCode::OK);
212  EXPECT_EQ(response.body, "OK1");
213 
214  request = {"/okxx", "GET", {}, ""};
215  response = {};
216 
217  EXPECT_TRUE(connection->BlockingSendRequest(request, &response));
218  EXPECT_EQ(response.status, HTTPStatusCode::OK);
219  EXPECT_EQ(response.body, "OK2");
220 
221  server->Terminate();
222  server->WaitForTermination();
223 }
224 
225 // Test RequestDispatcher in-order dispatching
226 TEST_F(EvHTTPServerTest, InOrderRequestDispather) {
227  auto dispatcher1 = [](ServerRequestInterface* request) {
228  return [](ServerRequestInterface* request) {
229  request->WriteResponseString("OK1");
230  request->Reply();
231  };
232  };
233 
234  auto dispatcher2 = [](ServerRequestInterface* request) {
235  return [](ServerRequestInterface* request) {
236  request->WriteResponseString("OK2");
237  request->Reply();
238  };
239  };
240 
241  server->RegisterRequestDispatcher(std::move(dispatcher1),
242  RequestHandlerOptions());
243  server->RegisterRequestDispatcher(std::move(dispatcher2),
244  RequestHandlerOptions());
245 
246  server->StartAcceptingRequests();
247 
248  auto connection =
249  TestEvHTTPConnection::Connect("localhost", server->listen_port());
250  ASSERT_TRUE(connection != nullptr);
251 
252  TestClientRequest request = {"/ok", "GET", {}, ""};
253  TestClientResponse response = {};
254 
255  EXPECT_TRUE(connection->BlockingSendRequest(request, &response));
256  EXPECT_EQ(response.status, HTTPStatusCode::OK);
257  EXPECT_EQ(response.body, "OK1");
258 
259  server->Terminate();
260  server->WaitForTermination();
261 }
262 
263 // Test handler interaction
264 TEST_F(EvHTTPServerTest, RequestHandlerInteraction) {
265  absl::Notification handler1_start;
266  auto handler1 = [&handler1_start](ServerRequestInterface* request) {
267  handler1_start.WaitForNotification();
268  request->WriteResponseString("OK1");
269  request->Reply();
270  };
271 
272  server->RegisterRequestHandler("/ok", std::move(handler1),
273  RequestHandlerOptions());
274 
275  server->StartAcceptingRequests();
276 
277  auto connection =
278  TestEvHTTPConnection::Connect("localhost", server->listen_port());
279  ASSERT_TRUE(connection != nullptr);
280  connection->SetExecutor(absl::make_unique<MyExecutor>(4));
281 
282  absl::Notification response_done;
283  TestClientRequest request = {"/ok", "GET", {}, ""};
284  TestClientResponse response = {};
285  response.done = [&response_done]() { response_done.Notify(); };
286 
287  EXPECT_TRUE(connection->SendRequest(request, &response));
288  EXPECT_FALSE(
289  response_done.WaitForNotificationWithTimeout(absl::Milliseconds(50)));
290 
291  handler1_start.Notify();
292  response_done.WaitForNotification();
293 
294  EXPECT_EQ(response.status, HTTPStatusCode::OK);
295  EXPECT_EQ(response.body, "OK1");
296 
297  connection->Terminate();
298 
299  server->Terminate();
300  server->WaitForTermination();
301 }
302 
303 // Test active-request count during shutdown
304 TEST_F(EvHTTPServerTest, ActiveRequestCountInShutdown) {
305  absl::Notification handler_enter;
306  absl::Notification handler_start;
307  auto handler = [&handler_enter,
308  &handler_start](ServerRequestInterface* request) {
309  handler_enter.Notify();
310  handler_start.WaitForNotification();
311  request->WriteResponseString("OK1");
312  request->Reply();
313  };
314 
315  server->RegisterRequestHandler("/ok", std::move(handler),
316  RequestHandlerOptions());
317 
318  server->StartAcceptingRequests();
319 
320  auto connection =
321  TestEvHTTPConnection::Connect("localhost", server->listen_port());
322  ASSERT_TRUE(connection != nullptr);
323  connection->SetExecutor(absl::make_unique<MyExecutor>(4));
324 
325  TestClientRequest request = {"/ok", "GET", {}, ""};
326  TestClientResponse response = {};
327 
328  EXPECT_TRUE(connection->SendRequest(request, &response));
329  handler_enter.WaitForNotification();
330 
331  server->Terminate();
332  EXPECT_FALSE(server->WaitForTerminationWithTimeout(absl::Milliseconds(50)));
333 
334  handler_start.Notify();
335  EXPECT_TRUE(server->WaitForTerminationWithTimeout(absl::Milliseconds(5000)));
336 
337  connection->Terminate();
338 
339  // response.status etc are undefined as the server is terminated
340 }
341 
342 } // namespace
343 } // namespace net_http
344 } // namespace serving
345 } // namespace tensorflow