diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a83176..9ccb6ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -348,6 +348,7 @@ tile_add_test(fiber_detail_scheduler_test "tile/fiber/detail/scheduler_test.cc") tile_add_test(base_internal_logging_test "tile/base/internal/logging_test.cc") tile_add_test(base_chrono_test "tile/base/chrono_test.cc") tile_add_test(init_override_flag_test "tile/init/override_flag_test.cc") + # tile_add_test("custom_http_client_test" "tests/http_client_test.cc") # tile_add_test(base_internal_time_keeper_test # "tile/base/internal/time_keeper_test.cc") endif(TILE_BUILD_TESTS) diff --git a/tests/http_client_test.cc b/tests/http_client_test.cc new file mode 100644 index 0000000..985050e --- /dev/null +++ b/tests/http_client_test.cc @@ -0,0 +1,47 @@ +#include "tile/net/http/http_client.h" + +#include "gtest/gtest.h" + +const std::string url = "http://127.0.0.1:8000/"; + +TEST(HttpClient, Request) { + tile::HttpClient client; + std::vector>> + v; + tile::HttpClient::RequestOptions options; + options.timeout = std::chrono::seconds(20); + + std::atomic count{0}; + + for (int i = 0; i != 1000; ++i) { + for (auto code : tile::AllHttpStatus) { + if (static_cast(code) < 200) { + continue; + } + + v.emplace_back( + client.AsyncGet(url + std::to_string(static_cast(code)), options) + .Then([&](std::expected &&res) { + int cnt = count.fetch_add(1) + 1; + TILE_LOG_INFO_EVERY_SECOND("complete {}", cnt); + return res; + })); + } + } + + int j = 0; + for (int i = 0; i != 1000; ++i) { + for (auto &code : tile::AllHttpStatus) { + if (static_cast(code) < 200) { + continue; + } + + auto resp = tile::future::BlockingGet(std::move(v[j++])); + + EXPECT_TRUE(resp) << tile::HttpClient::ErrorCodeToString(resp.error()); + EXPECT_EQ(resp->status(), code); + } + } +} diff --git a/tests/http_server.py b/tests/http_server.py new file mode 100644 index 0000000..446730c --- /dev/null +++ b/tests/http_server.py @@ -0,0 +1,24 @@ +#!/usr/bin/python3 +import http.server +import socket +import socketserver +from http.server import HTTPServer, BaseHTTPRequestHandler + +PORT = 8000 + +class Request(BaseHTTPRequestHandler): + def do_GET(self): + code = int(self.path.split("/")[1]) + + self.send_response(code) + self.send_header('Content-type', 'text/plain') + self.end_headers() + +class HTTPServer(socketserver.TCPServer): + def server_bind(self): + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.socket.bind(self.server_address) + +Handler = http.server.SimpleHTTPRequestHandler +with HTTPServer(("", PORT), Request) as httpd: + httpd.serve_forever() diff --git a/tile/init.cc b/tile/init.cc index e280072..4afaccf 100644 --- a/tile/init.cc +++ b/tile/init.cc @@ -53,31 +53,18 @@ int Start(int argc, char **argv, std::function cb, google::InstallFailureSignalHandler(); } - // Init gflags gflags::SetVersionString("0.1.0"); gflags::ParseCommandLineFlags(&argc, &argv, true); detail::ApplyFlagOverrider(); - auto gflags_handler = tile::make_unique_with_deleter( - [](void *) { gflags::ShutDownCommandLineFlags(); }); - // Init Glog google::InitGoogleLogging(argv[0]); - auto glog_handler = tile::make_unique_with_deleter( - [](void *) { google::ShutdownGoogleLogging(); }); TILE_LOG_INFO("Tile started."); TILE_PCHECK(signal(SIGPIPE, SIG_IGN) != SIG_ERR); - // Init BasicRuntime InitializeBasicRuntime(); - auto basic_runtime_handler = tile::make_unique_with_deleter( - [](void *) { TerminateBasicRuntime(); }); - - // Run all initializers detail::RunAllInitializers(); - auto initializers_handler = tile::make_unique_with_deleter( - [](void *) { detail::RunAllInitializers(); }); int rc = 0; @@ -100,9 +87,9 @@ int Start(int argc, char **argv, std::function cb, worker.join(); } - // detail::RunAllFinalizers(); - // TerminateBasicRuntime(); - // gflags::ShutDownCommandLineFlags(); + detail::RunAllFinalizers(); + TerminateBasicRuntime(); + gflags::ShutDownCommandLineFlags(); TILE_LOG_INFO("Exited"); return rc; diff --git a/tile/init/on_init.cc b/tile/init/on_init.cc index 7f0fbfa..3ad04b0 100644 --- a/tile/init/on_init.cc +++ b/tile/init/on_init.cc @@ -83,6 +83,7 @@ void RegisterOnInitCallback(std::int32_t priority, std::function init, !registry_prepared.load(std::memory_order_relaxed), "Callbacks may only be registered before `tile::Start()` is called"); auto &®istry = *GetStagingRegistry(); + TILE_CHECK(init != nullptr, "Initializer must be provided"); registry[priority].push_back({std::move(init), std::move(fini)}); } diff --git a/tile/net/http/http_client.cc b/tile/net/http/http_client.cc index 924500a..ade386f 100644 --- a/tile/net/http/http_client.cc +++ b/tile/net/http/http_client.cc @@ -49,10 +49,15 @@ HttpClient::ErrorCode GetErrorCodeFromCurlCode(int c) { return HttpClient::ERROR_IO; case CURLE_TOO_MANY_REDIRECTS: return HttpClient::ERROR_TOO_MANY_REDIRECTS; - default: - TILE_LOG_WARNING_EVERY_SECOND("ERROR_UNKNOWN CURLcode {}", c); + case CURLE_GOT_NOTHING: + return HttpClient::ERROR_GET_NOTHING; + + default: { + TILE_LOG_WARNING_EVERY_SECOND("ERROR_UNKNOWN CURLcode {}, curl msg: ", c, + curl_easy_strerror(static_cast(c))); return HttpClient::ERROR_UNKNOWN; } + } } long TileHttpVersionToCurlHttpVersion(HttpVersion v, @@ -446,6 +451,8 @@ const char *HttpClient::ErrorCodeToString(int error_code) { return "ERROR_INTERNAL_ERROR"; case ERROR_DRY_RUN: return "ERROR_DRY_RUN"; + case ERROR_GET_NOTHING: + return "ERROR_GET_NOTHING"; case ERROR_UNKNOWN: return ""; } diff --git a/tile/net/http/http_client.h b/tile/net/http/http_client.h index f9057f7..77eea63 100644 --- a/tile/net/http/http_client.h +++ b/tile/net/http/http_client.h @@ -11,6 +11,8 @@ #include "gflags/gflags_declare.h" +#include + DECLARE_int32(tile_http_client_default_timeout_ms); namespace tile { @@ -45,6 +47,7 @@ public: ERROR_IO, ERROR_INTERNAL_ERROR, ERROR_DRY_RUN, + ERROR_GET_NOTHING, ERROR_UNKNOWN = 100, }; diff --git a/tile/net/http/types.h b/tile/net/http/types.h index 7a9aa91..317181e 100644 --- a/tile/net/http/types.h +++ b/tile/net/http/types.h @@ -79,6 +79,28 @@ enum class HttpStatus { // `HttpStatusCode`? NetworkAuthenticationRequired = 511 }; +// AllHttpStatus for for_each +static HttpStatus AllHttpStatus[] = { + HttpStatus::Continue, + HttpStatus::SwitchingProtocols, + HttpStatus::EarlyHints, + HttpStatus::OK, + HttpStatus::Created, + HttpStatus::Accepted, + HttpStatus::NonAuthoritativeInformation, + HttpStatus::NoContent, + HttpStatus::ResetContent, + HttpStatus::PartialContent, + HttpStatus::MultipleChoices, + HttpStatus::MovedPermanently, + HttpStatus::Found, + HttpStatus::SeeOther, + HttpStatus::NotModified, + HttpStatus::TemporaryRedirect, + HttpStatus::PermanentRedirect, + HttpStatus::BadRequest, +}; + Slice ToSlice(HttpVersion method) noexcept; Slice ToSlice(HttpMethod) noexcept; Slice ToSlice(HttpStatus status) noexcept;