From 6232d13f5321b87ddf12a1aa36b4545da45f173d Mon Sep 17 00:00:00 2001 From: Joel Klinghed Date: Wed, 17 Nov 2021 22:34:57 +0100 Subject: Travel3: Simple image and video display site Reads the images and videos from filesystem and builds a site in memroy. --- test/test_transport_http.cc | 241 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 test/test_transport_http.cc (limited to 'test/test_transport_http.cc') diff --git a/test/test_transport_http.cc b/test/test_transport_http.cc new file mode 100644 index 0000000..9ce7820 --- /dev/null +++ b/test/test_transport_http.cc @@ -0,0 +1,241 @@ +#include "common.hh" + +#include "config.hh" +#include "file_test.hh" +#include "http_protocol.hh" +#include "io.hh" +#include "logger.hh" +#include "looper.hh" +#include "socket_test.hh" +#include "str_buffer.hh" +#include "strutil.hh" +#include "task_runner.hh" +#include "transport_http.hh" + +#include + +namespace { + +class TransportHttpTest : public SocketTest, public Transport::Handler { +public: + ~TransportHttpTest() override { + if (!path_.empty()) { + std::error_code err; + std::filesystem::remove(path_, err); + } + } + + void SetUp() override { + fd_ = FileTest::create_temp_file(std::string(), &path_); + + auto config = Config::create_empty(); + auto factory = create_transport_factory_http(); + handler_ = Transport::create_default_handler(logger_, this); + transport_ = factory->create(logger_, looper(), runner_, logger_.get(), + config.get(), handler_.get()); + } + + void TearDown() override { + transport_.reset(); + handler_.reset(); + runner_.reset(); + } + + void write_file(std::string_view content) { + ASSERT_TRUE(fd_); + auto buffer = make_strbuffer(content); + while (!buffer->empty()) { + ASSERT_TRUE(io::drain(buffer.get(), fd_.get())); + } + ASSERT_TRUE(io::close(fd_.release())); + } + + std::unique_ptr request( + Transport* transport, Transport::Request const* request) override { + if (request->method() == "GET") { + if (request->path() == "/hello_world") + return transport->create_ok_data("Hello World!"); + if (request->path() == "/file") + return transport->create_ok_file(path_); + } + return transport->create_not_found();; + } + + Transport* transport() { return transport_.get(); } + + Logger* logger() { return logger_.get(); } + +private: + std::shared_ptr logger_ = Logger::create_null(); + std::shared_ptr runner_ = TaskRunner::create(looper()); + std::unique_ptr handler_; + std::unique_ptr transport_; + std::filesystem::path path_; + unique_fd fd_; +}; + +void make_request(SocketTest::Client* cli, std::string const& path, + bool keep_conn) { + auto builder = HttpRequestBuilder::create( + "GET", path, "HTTP", Version(1, 1)); + if (!keep_conn) { + builder->add_header("Connection", "close"); + } + cli->write([&] (Buffer* buf) { + ASSERT_TRUE(builder->build(buf)); + }); +} + +struct Response { + std::unique_ptr response; + std::string content; + bool ended{false}; + + void reset() { + response.reset(); + content.clear(); + ended = false; + } +}; + +void read_response_content(SocketTest::Client* cli, Response* response) { + assert(!response->ended); + assert(response->response); + auto len_str = response->response->first_header("content-length"); + auto size = str::parse_uint64(len_str); + if (size) { + size_t need = *size - response->content.size(); + if (need == 0) { + response->ended = true; + return; + } + auto received = cli->received(); + if (received.size() < need) { + response->content.append(received); + cli->forget(received.size()); + return; + } + response->ended = true; + response->content.append(received.substr(0, need)); + cli->forget(need); + return; + } + + size_t old = response->content.size(); + response->content.append(cli->received()); + cli->forget(response->content.size() - old); + if (cli->closed()) + response->ended = true; +} + +void read_response(SocketTest::Client* cli, Response* response, + bool* need_more) { + if (!response->response) { + cli->read([&] (RoBuffer* buf) { + response->response = HttpResponse::parse(buf); + }); + if (!response->response) { + ASSERT_FALSE(cli->closed()); + *need_more = true; + return; + } + ASSERT_TRUE(response->response->good()); + } + read_response_content(cli, response); + if (!response->ended) { + ASSERT_FALSE(cli->closed()); + *need_more = true; + return; + } + *need_more = false; +} + +} // namespace + +TEST_F(TransportHttpTest, sanity) { + auto pair = create_pair(); + ASSERT_TRUE(pair.first && pair.second); + transport()->add_client(std::move(pair.first)); + auto cli = create_client(std::move(pair.second)); + + make_request(cli.get(), "/hello_world", false); + + Response response; + + while (true) { + bool need_more; + read_response(cli.get(), &response, &need_more); + if (need_more) { + cli->wait(logger()); + continue; + } else { + break; + } + } + + ASSERT_TRUE(response.response); + EXPECT_EQ(200, response.response->status_code()); + EXPECT_EQ("OK", response.response->status_message()); + EXPECT_EQ("HTTP", response.response->proto()); + EXPECT_EQ(1, response.response->proto_version().major); + EXPECT_EQ(1, response.response->proto_version().minor); + EXPECT_EQ("Hello World!", response.content); + if (!cli->closed()) + cli->wait(logger()); + EXPECT_TRUE(cli->closed()); +} + +TEST_F(TransportHttpTest, reuse_conn) { + write_file("foobar"); + + auto pair = create_pair(); + ASSERT_TRUE(pair.first && pair.second); + transport()->add_client(std::move(pair.first)); + auto cli = create_client(std::move(pair.second)); + + make_request(cli.get(), "/hello_world", true); + + Response response; + + while (true) { + bool need_more; + read_response(cli.get(), &response, &need_more); + if (need_more) { + cli->wait(logger()); + continue; + } else { + break; + } + } + + ASSERT_TRUE(response.response); + EXPECT_EQ(200, response.response->status_code()); + EXPECT_EQ("OK", response.response->status_message()); + EXPECT_EQ("HTTP", response.response->proto()); + EXPECT_EQ(1, response.response->proto_version().major); + EXPECT_EQ(1, response.response->proto_version().minor); + EXPECT_EQ("Hello World!", response.content); + + make_request(cli.get(), "/file", true); + + response.reset(); + + while (true) { + bool need_more; + read_response(cli.get(), &response, &need_more); + if (need_more) { + cli->wait(logger()); + continue; + } else { + break; + } + } + + ASSERT_TRUE(response.response); + EXPECT_EQ(200, response.response->status_code()); + EXPECT_EQ("OK", response.response->status_message()); + EXPECT_EQ("HTTP", response.response->proto()); + EXPECT_EQ(1, response.response->proto_version().major); + EXPECT_EQ(1, response.response->proto_version().minor); + EXPECT_EQ("foobar", response.content); +} -- cgit v1.2.3-70-g09d2