summaryrefslogtreecommitdiff
path: root/test/test_transport_http.cc
diff options
context:
space:
mode:
authorJoel Klinghed <the_jk@spawned.biz>2021-11-17 22:34:57 +0100
committerJoel Klinghed <the_jk@spawned.biz>2021-11-17 22:34:57 +0100
commit6232d13f5321b87ddf12a1aa36b4545da45f173d (patch)
tree23f3316470a14136debd9d02f9e920ca2b06f4cc /test/test_transport_http.cc
Travel3: Simple image and video display site
Reads the images and videos from filesystem and builds a site in memroy.
Diffstat (limited to 'test/test_transport_http.cc')
-rw-r--r--test/test_transport_http.cc241
1 files changed, 241 insertions, 0 deletions
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 <gtest/gtest.h>
+
+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<Transport::Response> 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_ = Logger::create_null();
+ std::shared_ptr<TaskRunner> runner_ = TaskRunner::create(looper());
+ std::unique_ptr<Transport::Handler> handler_;
+ std::unique_ptr<Transport> 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<HttpResponse> 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);
+}