diff --git a/autotest/CMakeLists.txt b/autotest/CMakeLists.txt index 3ada4cd..84cdbbb 100644 --- a/autotest/CMakeLists.txt +++ b/autotest/CMakeLists.txt @@ -2,6 +2,8 @@ set(AT_SRCS client_autotest.cc + client_timeout_autotest.cc + main.cc ) set(AT_TARGET_NAME webcc_autotest) diff --git a/autotest/client_autotest.cc b/autotest/client_autotest.cc index fbed4c0..db81134 100644 --- a/autotest/client_autotest.cc +++ b/autotest/client_autotest.cc @@ -9,7 +9,6 @@ #include "json/json.h" #include "webcc/client_session.h" -#include "webcc/logger.h" namespace bfs = boost::filesystem; @@ -458,13 +457,3 @@ TEST(ClientTest, KeepAlive) { std::cerr << error << std::endl; } } - -// ----------------------------------------------------------------------------- - -int main(int argc, char* argv[]) { - // Set webcc::LOG_CONSOLE to enable logging. - WEBCC_LOG_INIT("", 0); - - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/autotest/client_timeout_autotest.cc b/autotest/client_timeout_autotest.cc new file mode 100644 index 0000000..49a13ff --- /dev/null +++ b/autotest/client_timeout_autotest.cc @@ -0,0 +1,103 @@ +#include +#include + +#include "gtest/gtest.h" + +#include "webcc/client_session.h" +#include "webcc/response_builder.h" +#include "webcc/server.h" + +namespace { + +const char* kData = "Hello, World!"; + +const std::uint16_t kPort = 8080; + +std::shared_ptr g_server; +std::shared_ptr g_thread; + +class HelloView : public webcc::View { +public: + webcc::ResponsePtr Handle(webcc::RequestPtr request) override { + if (request->method() == "GET") { + if (request->args().size() != 1) { + return webcc::ResponseBuilder{}.BadRequest()(); + } + + int seconds = std::stoi(request->args()[0]); + if (seconds > 0) { + std::this_thread::sleep_for(std::chrono::seconds(seconds)); + } + + return webcc::ResponseBuilder{}.OK().Body(kData)(); + } + + return {}; + } +}; + +} // namespace + +class ClientTimeoutTest : public testing::Test { +public: + static void SetUpTestCase() { + g_server.reset(new webcc::Server{ kPort }); + + g_server->Route(webcc::R{ "/sleep/(\\d+)" }, + std::make_shared()); + + // Run the server in a separate thread. + g_thread.reset(new std::thread{ []() { g_server->Run(); } }); + } + + static void TearDownTestCase() { + if (g_server) { + g_server->Stop(); + } + if (g_thread) { + g_thread->join(); + } + } +}; + +TEST_F(ClientTimeoutTest, NoTimeout) { + webcc::ClientSession session; + + // Default timeout is 30s. + + try { + auto r = session.Send(webcc::RequestBuilder{}. + Get("http://localhost/sleep/0").Port(kPort) + ()); + + EXPECT_EQ(webcc::Status::kOK, r->status()); + EXPECT_EQ("OK", r->reason()); + + EXPECT_EQ(kData, r->data()); + + } catch (const webcc::Error& error) { + std::cerr << error << std::endl; + } +} + +TEST_F(ClientTimeoutTest, Timeout) { + webcc::ClientSession session; + + // Change timeout to 1s. + session.set_timeout(1); + + webcc::ResponsePtr r; + bool timeout = false; + + try { + r = session.Send(webcc::RequestBuilder{}. + Get("http://localhost/sleep/3").Port(kPort) + ()); + + } catch (const webcc::Error& error) { + timeout = error.timeout(); + } + + EXPECT_TRUE(!r); + EXPECT_TRUE(timeout); +} diff --git a/autotest/main.cc b/autotest/main.cc new file mode 100644 index 0000000..7ee7577 --- /dev/null +++ b/autotest/main.cc @@ -0,0 +1,11 @@ +#include "gtest/gtest.h" + +#include "webcc/logger.h" + +int main(int argc, char* argv[]) { + // Set webcc::LOG_CONSOLE to enable logging. + WEBCC_LOG_INIT("", 0); + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/webcc/request_builder.cc b/webcc/request_builder.cc index 763722e..51bb7d7 100644 --- a/webcc/request_builder.cc +++ b/webcc/request_builder.cc @@ -51,23 +51,6 @@ RequestPtr RequestBuilder::operator()() { return request; } -RequestBuilder& RequestBuilder::Url(const std::string& url, bool encode) { - url_ = webcc::Url{ url, encode }; - return *this; -} - -RequestBuilder& RequestBuilder::Path(const std::string& path, bool encode) { - url_.AppendPath(path, encode); - return *this; -} - -RequestBuilder& RequestBuilder::Query(const std::string& key, - const std::string& value, - bool encode) { - url_.AppendQuery(key, value, encode); - return *this; -} - RequestBuilder& RequestBuilder::File(const webcc::Path& path, bool infer_media_type, std::size_t chunk_size) { diff --git a/webcc/request_builder.h b/webcc/request_builder.h index 7ffca49..72cb632 100644 --- a/webcc/request_builder.h +++ b/webcc/request_builder.h @@ -66,14 +66,33 @@ public: return Method(methods::kPatch).Url(url, encode); } - RequestBuilder& Url(const std::string& url, bool encode = false); + RequestBuilder& Url(const std::string& url, bool encode = false) { + url_ = webcc::Url{ url, encode }; + return *this; + } + + RequestBuilder& Port(const std::string& port) { + url_.set_port(port); + return *this; + } + + RequestBuilder& Port(std::uint16_t port) { + url_.set_port(std::to_string(port)); + return *this; + } // Append a piece to the path. - RequestBuilder& Path(const std::string& path, bool encode = false); + RequestBuilder& Path(const std::string& path, bool encode = false) { + url_.AppendPath(path, encode); + return *this; + } // Append a parameter to the query. RequestBuilder& Query(const std::string& key, const std::string& value, - bool encode = false); + bool encode = false) { + url_.AppendQuery(key, value, encode); + return *this; + } RequestBuilder& MediaType(const std::string& media_type) { media_type_ = media_type; diff --git a/webcc/url.h b/webcc/url.h index fa342e3..a8e7a54 100644 --- a/webcc/url.h +++ b/webcc/url.h @@ -75,6 +75,10 @@ public: return query_; } + void set_port(const std::string& port) { + port_ = port; + } + // Append a piece of path. void AppendPath(const std::string& piece, bool encode = false);