From 672b2040688afb2a80f7576e6752f68351929b8f Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Tue, 21 Nov 2023 19:34:32 -0400 Subject: [PATCH] [WIP] Implement more tests Signed-off-by: Juan Cruz Viotti --- .../include/sourcemeta/hydra/http_request.h | 2 + .../include/sourcemeta/hydra/http_response.h | 1 + src/http/request.cc | 4 + src/http/response.cc | 8 +- test/http/request_1_1_test.cc | 106 +++++++++++++++++- test/http/stub.js | 25 ++--- 6 files changed, 130 insertions(+), 16 deletions(-) diff --git a/src/http/include/sourcemeta/hydra/http_request.h b/src/http/include/sourcemeta/hydra/http_request.h index 1411d8ef..b6b1e5ce 100644 --- a/src/http/include/sourcemeta/hydra/http_request.h +++ b/src/http/include/sourcemeta/hydra/http_request.h @@ -26,6 +26,8 @@ class SOURCEMETA_HYDRA_HTTP_EXPORT Request { auto capture(std::string header) -> void; auto capture(std::initializer_list headers) -> void; auto header(std::string_view key, std::string_view value) -> void; + auto header(std::string_view key, int value) -> void; + auto send() -> std::future; private: diff --git a/src/http/include/sourcemeta/hydra/http_response.h b/src/http/include/sourcemeta/hydra/http_response.h index 4415af64..3b622642 100644 --- a/src/http/include/sourcemeta/hydra/http_response.h +++ b/src/http/include/sourcemeta/hydra/http_response.h @@ -23,6 +23,7 @@ class SOURCEMETA_HYDRA_HTTP_EXPORT Response { auto status() const noexcept -> Status; auto header(const std::string &key) const -> std::optional; + auto empty() noexcept -> bool; auto body() -> std::istringstream &; private: diff --git a/src/http/request.cc b/src/http/request.cc index 6ee7838b..daaa10d1 100644 --- a/src/http/request.cc +++ b/src/http/request.cc @@ -35,6 +35,10 @@ auto Request::header(std::string_view key, std::string_view value) -> void { this->stream.header(key, value); } +auto Request::header(std::string_view key, int value) -> void { + this->stream.header(key, std::to_string(value)); +} + auto Request::send() -> std::future { std::ostringstream output; this->stream.on_data( diff --git a/src/http/response.cc b/src/http/response.cc index 555d1715..081ad8c2 100644 --- a/src/http/response.cc +++ b/src/http/response.cc @@ -1,6 +1,7 @@ #include #include +#include // assert #include // std::map #include // std::optional, std::nullopt #include // std::ostringstream, std::istringstream @@ -26,6 +27,11 @@ auto Response::header(const std::string &key) const return this->headers_.at(key); } -auto Response::body() -> std::istringstream & { return this->stream_; } +auto Response::empty() noexcept -> bool { return this->stream_.peek() == -1; } + +auto Response::body() -> std::istringstream & { + assert(!this->empty()); + return this->stream_; +} } // namespace sourcemeta::hydra::http diff --git a/test/http/request_1_1_test.cc b/test/http/request_1_1_test.cc index 5029bdff..dfb2b312 100644 --- a/test/http/request_1_1_test.cc +++ b/test/http/request_1_1_test.cc @@ -1,11 +1,115 @@ +#include +#include +#include +#include + #include #include // TODO: Add more tests +// - Request body +// - Response body +// - Request header +// - Response header with capture +// - Response header without capture +// - Response header with partial intersection capture + +static auto body(sourcemeta::hydra::http::Response &response) -> std::string { + std::ostringstream result; + std::copy( + std::istreambuf_iterator(response.body()), + std::istreambuf_iterator(), + std::ostreambuf_iterator(result)); + return result.str(); +} -TEST(HTTP_Request_1_1, XXX) { +TEST(HTTP_Request_1_1, GET_root) { sourcemeta::hydra::http::Request request{BASE_URL}; request.method(sourcemeta::hydra::http::Method::GET); sourcemeta::hydra::http::Response response{request.send().get()}; EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK); + EXPECT_FALSE(response.empty()); + EXPECT_EQ(body(response), "RECEIVED GET /"); +} + +TEST(HTTP_Request_1_1, HEAD_root) { + sourcemeta::hydra::http::Request request{BASE_URL}; + request.method(sourcemeta::hydra::http::Method::HEAD); + sourcemeta::hydra::http::Response response{request.send().get()}; + EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK); + EXPECT_TRUE(response.empty()); +} + +TEST(HTTP_Request_1_1, POST_root) { + sourcemeta::hydra::http::Request request{BASE_URL}; + request.method(sourcemeta::hydra::http::Method::POST); + sourcemeta::hydra::http::Response response{request.send().get()}; + EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK); + EXPECT_FALSE(response.empty()); + EXPECT_EQ(body(response), "RECEIVED POST /"); +} + +TEST(HTTP_Request_1_1, PUT_root) { + sourcemeta::hydra::http::Request request{BASE_URL}; + request.method(sourcemeta::hydra::http::Method::PUT); + sourcemeta::hydra::http::Response response{request.send().get()}; + EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK); + EXPECT_FALSE(response.empty()); + EXPECT_EQ(body(response), "RECEIVED PUT /"); +} + +TEST(HTTP_Request_1_1, DELETE_root) { + sourcemeta::hydra::http::Request request{BASE_URL}; + request.method(sourcemeta::hydra::http::Method::DELETE); + sourcemeta::hydra::http::Response response{request.send().get()}; + EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK); + EXPECT_FALSE(response.empty()); + EXPECT_EQ(body(response), "RECEIVED DELETE /"); +} + +TEST(HTTP_Request_1_1, OPTIONS_root) { + sourcemeta::hydra::http::Request request{BASE_URL}; + request.method(sourcemeta::hydra::http::Method::OPTIONS); + sourcemeta::hydra::http::Response response{request.send().get()}; + EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK); + EXPECT_FALSE(response.empty()); + EXPECT_EQ(body(response), "RECEIVED OPTIONS /"); +} + +TEST(HTTP_Request_1_1, TRACE_root) { + sourcemeta::hydra::http::Request request{BASE_URL}; + request.method(sourcemeta::hydra::http::Method::TRACE); + sourcemeta::hydra::http::Response response{request.send().get()}; + EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK); + EXPECT_FALSE(response.empty()); + EXPECT_EQ(body(response), "RECEIVED TRACE /"); +} + +TEST(HTTP_Request_1_1, PATCH_root) { + sourcemeta::hydra::http::Request request{BASE_URL}; + request.method(sourcemeta::hydra::http::Method::PATCH); + sourcemeta::hydra::http::Response response{request.send().get()}; + EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::OK); + EXPECT_FALSE(response.empty()); + EXPECT_EQ(body(response), "RECEIVED PATCH /"); +} + +TEST(HTTP_Request_1_1, GET_root_custom_code_string) { + sourcemeta::hydra::http::Request request{BASE_URL}; + request.method(sourcemeta::hydra::http::Method::GET); + request.header("X-Code", "400"); + sourcemeta::hydra::http::Response response{request.send().get()}; + EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::BAD_REQUEST); + EXPECT_FALSE(response.empty()); + EXPECT_EQ(body(response), "RECEIVED GET /"); +} + +TEST(HTTP_Request_1_1, GET_root_custom_code_integer) { + sourcemeta::hydra::http::Request request{BASE_URL}; + request.method(sourcemeta::hydra::http::Method::GET); + request.header("X-Code", 400); + sourcemeta::hydra::http::Response response{request.send().get()}; + EXPECT_EQ(response.status(), sourcemeta::hydra::http::Status::BAD_REQUEST); + EXPECT_FALSE(response.empty()); + EXPECT_EQ(body(response), "RECEIVED GET /"); } diff --git a/test/http/stub.js b/test/http/stub.js index 8e134ecb..98709d6a 100644 --- a/test/http/stub.js +++ b/test/http/stub.js @@ -1,20 +1,17 @@ const http = require('http'); +const PORT = 9999; -const server = http.createServer((req, res) => { - // Set the response header to indicate JSON content - res.setHeader('Content-Type', 'application/json'); - - // Define a simple JSON response - const jsonResponse = { - message: 'Hello, JSON World!', - timestamp: new Date().toISOString(), - }; +http.createServer((request, response) => { + for (const [key, value] of Object.entries(request.headers)) { + response.setHeader(`X-${key}`, value); + } - // Send the JSON response - res.end(JSON.stringify(jsonResponse)); -}); + if (request.headers['x-code']) { + response.statusCode = parseInt(request.headers['x-code'], 10); + } -const PORT = 9999; -server.listen(PORT, () => { + response.setHeader('Content-Type', 'text/plain'); + response.end(`RECEIVED ${request.method} ${request.url}`); +}).listen(PORT, () => { console.log(`Server is listening on port ${PORT}`); });