Fix test failures introduced by PR #113697 (#116941)
[llvm-project.git] / llvm / unittests / Debuginfod / HTTPServerTests.cpp
blobcd1d5f2d9fc7003ad5177b05c94fb4b03309b82f
1 //===-- llvm/unittest/Support/HTTPServer.cpp - unit tests -------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ADT/StringExtras.h"
10 #include "llvm/Debuginfod/HTTPClient.h"
11 #include "llvm/Debuginfod/HTTPServer.h"
12 #include "llvm/Support/Error.h"
13 #include "llvm/Support/ThreadPool.h"
14 #include "llvm/Testing/Support/Error.h"
15 #include "gmock/gmock.h"
16 #include "gtest/gtest.h"
18 using namespace llvm;
20 #ifdef LLVM_ENABLE_HTTPLIB
22 TEST(HTTPServer, IsAvailable) { EXPECT_TRUE(HTTPServer::isAvailable()); }
24 HTTPResponse Response = {200u, "text/plain", "hello, world\n"};
25 std::string UrlPathPattern = R"(/(.*))";
26 std::string InvalidUrlPathPattern = R"(/(.*)";
28 HTTPRequestHandler Handler = [](HTTPServerRequest &Request) {
29 Request.setResponse(Response);
32 HTTPRequestHandler DelayHandler = [](HTTPServerRequest &Request) {
33 std::this_thread::sleep_for(std::chrono::milliseconds(50));
34 Request.setResponse(Response);
37 HTTPRequestHandler StreamingHandler = [](HTTPServerRequest &Request) {
38 Request.setResponse({200, "text/plain", Response.Body.size(),
39 [=](size_t Offset, size_t Length) -> StringRef {
40 return Response.Body.substr(Offset, Length);
41 }});
44 TEST(HTTPServer, InvalidUrlPath) {
45 // test that we can bind to any address
46 HTTPServer Server;
47 EXPECT_THAT_ERROR(Server.get(InvalidUrlPathPattern, Handler),
48 Failed<StringError>());
49 EXPECT_THAT_EXPECTED(Server.bind(), Succeeded());
52 TEST(HTTPServer, bind) {
53 // test that we can bind to any address
54 HTTPServer Server;
55 EXPECT_THAT_ERROR(Server.get(UrlPathPattern, Handler), Succeeded());
56 EXPECT_THAT_EXPECTED(Server.bind(), Succeeded());
59 TEST(HTTPServer, ListenBeforeBind) {
60 // test that we can bind to any address
61 HTTPServer Server;
62 EXPECT_THAT_ERROR(Server.get(UrlPathPattern, Handler), Succeeded());
63 EXPECT_THAT_ERROR(Server.listen(), Failed<StringError>());
66 #ifdef LLVM_ENABLE_CURL
67 // Test the client and server against each other.
69 // Test fixture to initialize and teardown the HTTP client for each
70 // client-server test
71 class HTTPClientServerTest : public ::testing::Test {
72 protected:
73 void SetUp() override { HTTPClient::initialize(); }
74 void TearDown() override { HTTPClient::cleanup(); }
77 /// A simple handler which writes returned data to a string.
78 struct StringHTTPResponseHandler final : public HTTPResponseHandler {
79 std::string ResponseBody = "";
80 /// These callbacks store the body and status code in an HTTPResponseBuffer
81 /// allocated based on Content-Length. The Content-Length header must be
82 /// handled by handleHeaderLine before any calls to handleBodyChunk.
83 Error handleBodyChunk(StringRef BodyChunk) override {
84 ResponseBody = ResponseBody + BodyChunk.str();
85 return Error::success();
89 TEST_F(HTTPClientServerTest, Hello) {
90 HTTPServer Server;
91 EXPECT_THAT_ERROR(Server.get(UrlPathPattern, Handler), Succeeded());
92 Expected<unsigned> PortOrErr = Server.bind();
93 EXPECT_THAT_EXPECTED(PortOrErr, Succeeded());
94 unsigned Port = *PortOrErr;
95 DefaultThreadPool Pool(hardware_concurrency(1));
96 Pool.async([&]() { EXPECT_THAT_ERROR(Server.listen(), Succeeded()); });
97 std::string Url = "http://localhost:" + utostr(Port);
98 HTTPRequest Request(Url);
99 StringHTTPResponseHandler Handler;
100 HTTPClient Client;
101 EXPECT_THAT_ERROR(Client.perform(Request, Handler), Succeeded());
102 EXPECT_EQ(Handler.ResponseBody, Response.Body);
103 EXPECT_EQ(Client.responseCode(), Response.Code);
104 Server.stop();
107 TEST_F(HTTPClientServerTest, LambdaHandlerHello) {
108 HTTPServer Server;
109 HTTPResponse LambdaResponse = {200u, "text/plain",
110 "hello, world from a lambda\n"};
111 EXPECT_THAT_ERROR(Server.get(UrlPathPattern,
112 [LambdaResponse](HTTPServerRequest &Request) {
113 Request.setResponse(LambdaResponse);
115 Succeeded());
116 Expected<unsigned> PortOrErr = Server.bind();
117 EXPECT_THAT_EXPECTED(PortOrErr, Succeeded());
118 unsigned Port = *PortOrErr;
119 DefaultThreadPool Pool(hardware_concurrency(1));
120 Pool.async([&]() { EXPECT_THAT_ERROR(Server.listen(), Succeeded()); });
121 std::string Url = "http://localhost:" + utostr(Port);
122 HTTPRequest Request(Url);
123 StringHTTPResponseHandler Handler;
124 HTTPClient Client;
125 EXPECT_THAT_ERROR(Client.perform(Request, Handler), Succeeded());
126 EXPECT_EQ(Handler.ResponseBody, LambdaResponse.Body);
127 EXPECT_EQ(Client.responseCode(), LambdaResponse.Code);
128 Server.stop();
131 // Test the streaming response.
132 TEST_F(HTTPClientServerTest, StreamingHello) {
133 HTTPServer Server;
134 EXPECT_THAT_ERROR(Server.get(UrlPathPattern, StreamingHandler), Succeeded());
135 Expected<unsigned> PortOrErr = Server.bind();
136 EXPECT_THAT_EXPECTED(PortOrErr, Succeeded());
137 unsigned Port = *PortOrErr;
138 DefaultThreadPool Pool(hardware_concurrency(1));
139 Pool.async([&]() { EXPECT_THAT_ERROR(Server.listen(), Succeeded()); });
140 std::string Url = "http://localhost:" + utostr(Port);
141 HTTPRequest Request(Url);
142 StringHTTPResponseHandler Handler;
143 HTTPClient Client;
144 EXPECT_THAT_ERROR(Client.perform(Request, Handler), Succeeded());
145 EXPECT_EQ(Handler.ResponseBody, Response.Body);
146 EXPECT_EQ(Client.responseCode(), Response.Code);
147 Server.stop();
150 // Writes a temporary file and streams it back using streamFile.
151 HTTPRequestHandler TempFileStreamingHandler = [](HTTPServerRequest Request) {
152 int FD;
153 SmallString<64> TempFilePath;
154 sys::fs::createTemporaryFile("http-stream-file-test", "temp", FD,
155 TempFilePath);
156 raw_fd_ostream OS(FD, true, /*unbuffered=*/true);
157 OS << Response.Body;
158 OS.close();
159 streamFile(Request, TempFilePath);
162 // Test streaming back chunks of a file.
163 TEST_F(HTTPClientServerTest, StreamingFileResponse) {
164 HTTPServer Server;
165 EXPECT_THAT_ERROR(Server.get(UrlPathPattern, TempFileStreamingHandler),
166 Succeeded());
167 Expected<unsigned> PortOrErr = Server.bind();
168 EXPECT_THAT_EXPECTED(PortOrErr, Succeeded());
169 unsigned Port = *PortOrErr;
170 DefaultThreadPool Pool(hardware_concurrency(1));
171 Pool.async([&]() { EXPECT_THAT_ERROR(Server.listen(), Succeeded()); });
172 std::string Url = "http://localhost:" + utostr(Port);
173 HTTPRequest Request(Url);
174 StringHTTPResponseHandler Handler;
175 HTTPClient Client;
176 EXPECT_THAT_ERROR(Client.perform(Request, Handler), Succeeded());
177 EXPECT_EQ(Handler.ResponseBody, Response.Body);
178 EXPECT_EQ(Client.responseCode(), Response.Code);
179 Server.stop();
182 // Deletes the temporary file before streaming it back, should give a 404 not
183 // found status code.
184 HTTPRequestHandler MissingTempFileStreamingHandler =
185 [](HTTPServerRequest Request) {
186 int FD;
187 SmallString<64> TempFilePath;
188 sys::fs::createTemporaryFile("http-stream-file-test", "temp", FD,
189 TempFilePath);
190 raw_fd_ostream OS(FD, true, /*unbuffered=*/true);
191 OS << Response.Body;
192 OS.close();
193 // delete the file
194 sys::fs::remove(TempFilePath);
195 streamFile(Request, TempFilePath);
198 // Streaming a missing file should give a 404.
199 TEST_F(HTTPClientServerTest, StreamingMissingFileResponse) {
200 HTTPServer Server;
201 EXPECT_THAT_ERROR(Server.get(UrlPathPattern, MissingTempFileStreamingHandler),
202 Succeeded());
203 Expected<unsigned> PortOrErr = Server.bind();
204 EXPECT_THAT_EXPECTED(PortOrErr, Succeeded());
205 unsigned Port = *PortOrErr;
206 DefaultThreadPool Pool(hardware_concurrency(1));
207 Pool.async([&]() { EXPECT_THAT_ERROR(Server.listen(), Succeeded()); });
208 std::string Url = "http://localhost:" + utostr(Port);
209 HTTPRequest Request(Url);
210 StringHTTPResponseHandler Handler;
211 HTTPClient Client;
212 EXPECT_THAT_ERROR(Client.perform(Request, Handler), Succeeded());
213 EXPECT_EQ(Client.responseCode(), 404u);
214 Server.stop();
217 TEST_F(HTTPClientServerTest, ClientTimeout) {
218 HTTPServer Server;
219 EXPECT_THAT_ERROR(Server.get(UrlPathPattern, DelayHandler), Succeeded());
220 Expected<unsigned> PortOrErr = Server.bind();
221 EXPECT_THAT_EXPECTED(PortOrErr, Succeeded());
222 unsigned Port = *PortOrErr;
223 DefaultThreadPool Pool(hardware_concurrency(1));
224 Pool.async([&]() { EXPECT_THAT_ERROR(Server.listen(), Succeeded()); });
225 std::string Url = "http://localhost:" + utostr(Port);
226 HTTPClient Client;
227 // Timeout below 50ms, request should fail
228 Client.setTimeout(std::chrono::milliseconds(40));
229 HTTPRequest Request(Url);
230 StringHTTPResponseHandler Handler;
231 EXPECT_THAT_ERROR(Client.perform(Request, Handler), Failed<StringError>());
232 Server.stop();
235 // Check that Url paths are dispatched to the first matching handler and provide
236 // the correct path pattern match components.
237 TEST_F(HTTPClientServerTest, PathMatching) {
238 HTTPServer Server;
240 EXPECT_THAT_ERROR(
241 Server.get(R"(/abc/(.*)/(.*))",
242 [&](HTTPServerRequest &Request) {
243 EXPECT_EQ(Request.UrlPath, "/abc/1/2");
244 ASSERT_THAT(Request.UrlPathMatches,
245 testing::ElementsAre("1", "2"));
246 Request.setResponse({200u, "text/plain", Request.UrlPath});
248 Succeeded());
249 EXPECT_THAT_ERROR(Server.get(UrlPathPattern,
250 [&](HTTPServerRequest &Request) {
251 llvm_unreachable(
252 "Should not reach this handler");
253 Handler(Request);
255 Succeeded());
257 Expected<unsigned> PortOrErr = Server.bind();
258 EXPECT_THAT_EXPECTED(PortOrErr, Succeeded());
259 unsigned Port = *PortOrErr;
260 DefaultThreadPool Pool(hardware_concurrency(1));
261 Pool.async([&]() { EXPECT_THAT_ERROR(Server.listen(), Succeeded()); });
262 std::string Url = "http://localhost:" + utostr(Port) + "/abc/1/2";
263 HTTPRequest Request(Url);
264 StringHTTPResponseHandler Handler;
265 HTTPClient Client;
266 EXPECT_THAT_ERROR(Client.perform(Request, Handler), Succeeded());
267 EXPECT_EQ(Handler.ResponseBody, "/abc/1/2");
268 EXPECT_EQ(Client.responseCode(), 200u);
269 Server.stop();
272 TEST_F(HTTPClientServerTest, FirstPathMatched) {
273 HTTPServer Server;
275 EXPECT_THAT_ERROR(
276 Server.get(UrlPathPattern,
277 [&](HTTPServerRequest Request) { Handler(Request); }),
278 Succeeded());
280 EXPECT_THAT_ERROR(
281 Server.get(R"(/abc/(.*)/(.*))",
282 [&](HTTPServerRequest Request) {
283 EXPECT_EQ(Request.UrlPathMatches.size(), 2u);
284 llvm_unreachable("Should not reach this handler");
285 Request.setResponse({200u, "text/plain", Request.UrlPath});
287 Succeeded());
289 Expected<unsigned> PortOrErr = Server.bind();
290 EXPECT_THAT_EXPECTED(PortOrErr, Succeeded());
291 unsigned Port = *PortOrErr;
292 DefaultThreadPool Pool(hardware_concurrency(1));
293 Pool.async([&]() { EXPECT_THAT_ERROR(Server.listen(), Succeeded()); });
294 std::string Url = "http://localhost:" + utostr(Port) + "/abc/1/2";
295 HTTPRequest Request(Url);
296 StringHTTPResponseHandler Handler;
297 HTTPClient Client;
298 EXPECT_THAT_ERROR(Client.perform(Request, Handler), Succeeded());
299 EXPECT_EQ(Handler.ResponseBody, Response.Body);
300 EXPECT_EQ(Client.responseCode(), Response.Code);
301 Server.stop();
304 #endif
306 #else
308 TEST(HTTPServer, IsAvailable) { EXPECT_FALSE(HTTPServer::isAvailable()); }
310 #endif // LLVM_ENABLE_HTTPLIB