brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.5 KiB · cd1d5f2 Raw
311 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 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"17 18using namespace llvm;19 20#ifdef LLVM_ENABLE_HTTPLIB21 22TEST(HTTPServer, IsAvailable) { EXPECT_TRUE(HTTPServer::isAvailable()); }23 24HTTPResponse Response = {200u, "text/plain", "hello, world\n"};25std::string UrlPathPattern = R"(/(.*))";26std::string InvalidUrlPathPattern = R"(/(.*)";27 28HTTPRequestHandler Handler = [](HTTPServerRequest &Request) {29  Request.setResponse(Response);30};31 32HTTPRequestHandler DelayHandler = [](HTTPServerRequest &Request) {33  std::this_thread::sleep_for(std::chrono::milliseconds(50));34  Request.setResponse(Response);35};36 37HTTPRequestHandler 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                       }});42};43 44TEST(HTTPServer, InvalidUrlPath) {45  // test that we can bind to any address46  HTTPServer Server;47  EXPECT_THAT_ERROR(Server.get(InvalidUrlPathPattern, Handler),48                    Failed<StringError>());49  EXPECT_THAT_EXPECTED(Server.bind(), Succeeded());50}51 52TEST(HTTPServer, bind) {53  // test that we can bind to any address54  HTTPServer Server;55  EXPECT_THAT_ERROR(Server.get(UrlPathPattern, Handler), Succeeded());56  EXPECT_THAT_EXPECTED(Server.bind(), Succeeded());57}58 59TEST(HTTPServer, ListenBeforeBind) {60  // test that we can bind to any address61  HTTPServer Server;62  EXPECT_THAT_ERROR(Server.get(UrlPathPattern, Handler), Succeeded());63  EXPECT_THAT_ERROR(Server.listen(), Failed<StringError>());64}65 66#ifdef LLVM_ENABLE_CURL67// Test the client and server against each other.68 69// Test fixture to initialize and teardown the HTTP client for each70// client-server test71class HTTPClientServerTest : public ::testing::Test {72protected:73  void SetUp() override { HTTPClient::initialize(); }74  void TearDown() override { HTTPClient::cleanup(); }75};76 77/// A simple handler which writes returned data to a string.78struct StringHTTPResponseHandler final : public HTTPResponseHandler {79  std::string ResponseBody = "";80  /// These callbacks store the body and status code in an HTTPResponseBuffer81  /// allocated based on Content-Length. The Content-Length header must be82  /// handled by handleHeaderLine before any calls to handleBodyChunk.83  Error handleBodyChunk(StringRef BodyChunk) override {84    ResponseBody = ResponseBody + BodyChunk.str();85    return Error::success();86  }87};88 89TEST_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();105}106 107TEST_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);114                               }),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();129}130 131// Test the streaming response.132TEST_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();148}149 150// Writes a temporary file and streams it back using streamFile.151HTTPRequestHandler 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);160};161 162// Test streaming back chunks of a file.163TEST_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();180}181 182// Deletes the temporary file before streaming it back, should give a 404 not183// found status code.184HTTPRequestHandler 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 file194      sys::fs::remove(TempFilePath);195      streamFile(Request, TempFilePath);196    };197 198// Streaming a missing file should give a 404.199TEST_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();215}216 217TEST_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 fail228  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();233}234 235// Check that Url paths are dispatched to the first matching handler and provide236// the correct path pattern match components.237TEST_F(HTTPClientServerTest, PathMatching) {238  HTTPServer Server;239 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});247                 }),248      Succeeded());249  EXPECT_THAT_ERROR(Server.get(UrlPathPattern,250                               [&](HTTPServerRequest &Request) {251                                 llvm_unreachable(252                                     "Should not reach this handler");253                                 Handler(Request);254                               }),255                    Succeeded());256 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();270}271 272TEST_F(HTTPClientServerTest, FirstPathMatched) {273  HTTPServer Server;274 275  EXPECT_THAT_ERROR(276      Server.get(UrlPathPattern,277                 [&](HTTPServerRequest Request) { Handler(Request); }),278      Succeeded());279 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});286                 }),287      Succeeded());288 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();302}303 304#endif305 306#else307 308TEST(HTTPServer, IsAvailable) { EXPECT_FALSE(HTTPServer::isAvailable()); }309 310#endif // LLVM_ENABLE_HTTPLIB311