Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Http client ut #4966

Merged
merged 7 commits into from
Dec 1, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions src/common/http/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,10 @@ nebula_add_test(
OBJECTS
$<TARGET_OBJECTS:base_obj>
$<TARGET_OBJECTS:http_client_obj>
$<TARGET_OBJECTS:ws_obj>
$<TARGET_OBJECTS:ws_common_obj>
$<TARGET_OBJECTS:process_obj>
$<TARGET_OBJECTS:fs_obj>
$<TARGET_OBJECTS:stats_obj>
$<TARGET_OBJECTS:time_obj>
$<TARGET_OBJECTS:version_obj>
$<TARGET_OBJECTS:datatypes_obj>
$<TARGET_OBJECTS:wkt_wkb_io_obj>
$<TARGET_OBJECTS:fake_http_server_obj>
LIBRARIES
${PROXYGEN_LIBRARIES}
gtest
curl

gtest_main
)
119 changes: 39 additions & 80 deletions src/common/http/test/HttpClientTest.cpp
Original file line number Diff line number Diff line change
@@ -1,95 +1,54 @@
/* Copyright (c) 2019 vesoft inc. All rights reserved.
/* Copyright (c) 2022 vesoft inc. All rights reserved.
*
* This source code is licensed under Apache 2.0 License.
*/

#include <gtest/gtest.h>
#include <proxygen/httpserver/RequestHandler.h>
#include <proxygen/httpserver/ResponseBuilder.h>

#include "common/http/HttpClient.h"
#include "webservice/Common.h"
#include "webservice/Router.h"
#include "webservice/WebService.h"
#include "gtest/gtest.h"
#include "mock/FakeHttpServer.h"

namespace nebula {
namespace http {

class HttpClientHandler : public proxygen::RequestHandler {
public:
HttpClientHandler() = default;

void onRequest(std::unique_ptr<proxygen::HTTPMessage>) noexcept override {}

void onBody(std::unique_ptr<folly::IOBuf>) noexcept override {}

void onEOM() noexcept override {
proxygen::ResponseBuilder(downstream_)
.status(WebServiceUtils::to(HttpStatusCode::OK),
WebServiceUtils::toString(HttpStatusCode::OK))
.body("HttpClientHandler successfully")
.sendWithEOM();
}

void onUpgrade(proxygen::UpgradeProtocol) noexcept override {}

void requestComplete() noexcept override {
delete this;
}

void onError(proxygen::ProxygenError error) noexcept override {
LOG(ERROR) << "HttpClientHandler Error: " << proxygen::getErrorString(error);
}
};
class HttpClientTestEnv : public ::testing::Environment {
public:
void SetUp() override {
FLAGS_ws_ip = "127.0.0.1";
FLAGS_ws_http_port = 0;
LOG(INFO) << "Starting web service...";
webSvc_ = std::make_unique<WebService>();
class HTTPClientTest : public ::testing::Test {};

auto& router = webSvc_->router();
router.get("/path").handler([](auto&&) { return new HttpClientHandler(); });

auto status = webSvc_->start();
ASSERT_TRUE(status.ok()) << status;
}
TEST_F(HTTPClientTest, GET) {
FakeHttpServer server(3659);
server.start();
auto resp = HttpClient::get("http://localhost:3659");
ASSERT_EQ(resp.curlCode, 0) << resp.curlMessage;
ASSERT_EQ(resp.body, "GET");
server.stop();
server.join();
}

void TearDown() override {
webSvc_.reset();
VLOG(1) << "Web service stopped";
}
TEST_F(HTTPClientTest, POST) {
FakeHttpServer server(3660);
server.start();
auto resp = HttpClient::post("http://localhost:3660", {}, "");
ASSERT_EQ(resp.curlCode, 0) << resp.curlMessage;
ASSERT_EQ(resp.body, "POST");
server.stop();
server.join();
}

private:
std::unique_ptr<WebService> webSvc_;
};
TEST_F(HTTPClientTest, DELETE) {
FakeHttpServer server(3661);
server.start();
auto resp = HttpClient::delete_("http://localhost:3661", {});
ASSERT_EQ(resp.curlCode, 0) << resp.curlMessage;
ASSERT_EQ(resp.body, "DELETE");
server.stop();
server.join();
}

TEST(HttpClient, get) {
{
auto url =
folly::stringPrintf("http://%s:%d%s", FLAGS_ws_ip.c_str(), FLAGS_ws_http_port, "/path");
auto httpResp = HttpClient::get(url);
ASSERT_EQ(httpResp.curlCode, 0);
ASSERT_EQ("HttpClientHandler successfully", httpResp.body);
}
{
auto url = folly::stringPrintf(
"http://%s:%d%s", FLAGS_ws_ip.c_str(), FLAGS_ws_http_port, "/not_exist");
auto httpResp = HttpClient::get(url);
ASSERT_EQ(httpResp.curlCode, 0);
ASSERT_TRUE(httpResp.body.empty());
}
TEST_F(HTTPClientTest, PUT) {
FakeHttpServer server(3662);
server.start();
auto resp = HttpClient::put("http://localhost:3662", {}, "");
ASSERT_EQ(resp.curlCode, 0) << resp.curlMessage;
ASSERT_EQ(resp.body, "PUT");
server.stop();
server.join();
}

} // namespace http
} // namespace nebula

int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
folly::init(&argc, &argv, true);
google::SetStderrLogging(google::INFO);

::testing::AddGlobalTestEnvironment(new nebula::http::HttpClientTestEnv());
return RUN_ALL_TESTS();
}
12 changes: 12 additions & 0 deletions src/mock/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,15 @@ nebula_add_library(
)


nebula_add_library(
fake_http_server_obj OBJECT
FakeHttpServer.cpp
)

# nebula_add_executable(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe remove this, LGTM

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

# NAME fake_http_server
# SOURCES main.cpp
# OBJECTS $<TARGET_OBJECTS:fake_http_server_obj>
# LIBRARIES ${PROXYGEN_LIBRARIES}
# )

100 changes: 100 additions & 0 deletions src/mock/FakeHttpServer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/* Copyright (c) 2022 vesoft inc. All rights reserved.
*
* This source code is licensed under Apache 2.0 License.
*/
#include "mock/FakeHttpServer.h"

#include "folly/synchronization/Baton.h"
#include "glog/logging.h"
#include "proxygen/httpserver/HTTPServer.h"
#include "proxygen/httpserver/HTTPServerOptions.h"
#include "proxygen/httpserver/ResponseBuilder.h"

namespace nebula {

void FakeHttpHandler::onRequest(std::unique_ptr<proxygen::HTTPMessage> message) noexcept {
CHECK(message->getMethod());
method_ = message->getMethod().value();
auto headers = message->extractHeaders();
headers.forEach(
[this](std::string name, std::string value) { this->headers_.emplace_back(name, value); });
}

void FakeHttpHandler::onBody(std::unique_ptr<folly::IOBuf> buf) noexcept {
if (body_) {
body_->appendChain(std::move(buf));
} else {
body_ = std::move(buf);
}
}

void FakeHttpHandler::onEOM() noexcept {
std::tuple<int, std::map<std::string, std::string>, std::string> result;
switch (method_) {
case ::proxygen::HTTPMethod::PUT:
result = onPut();
break;
case ::proxygen::HTTPMethod::GET:
result = onGet();
break;
case ::proxygen::HTTPMethod::POST:
result = onPost();
break;
case ::proxygen::HTTPMethod::DELETE:
result = onDelete();
break;
default:
CHECK(false);
break;
}
auto builder = ::proxygen::ResponseBuilder(downstream_);
builder.status(std::get<0>(result), "");
for (auto& [name, value] : std::get<1>(result)) {
builder.header(name, value);
}
builder.body(std::get<2>(result));
builder.sendWithEOM();
}

void FakeHttpHandler::onUpgrade(proxygen::UpgradeProtocol) noexcept {
// Do nothing
}

void FakeHttpHandler::requestComplete() noexcept {
delete this;
}

void FakeHttpHandler::onError(proxygen::ProxygenError err) noexcept {
LOG(FATAL) << ::proxygen::getErrorString(err);
}

FakeHttpServer::FakeHttpServer(int port) : port_(port) {}

void FakeHttpServer::start() {
::proxygen::HTTPServerOptions options;
options.threads = 2;
options.idleTimeout = std::chrono::milliseconds(60000);
options.enableContentCompression = false;
options.handlerFactories =
proxygen::RequestHandlerChain().addThen<FakeHttpHandlerFactory>().build();
options.h2cEnabled = true;

server_ = std::make_unique<::proxygen::HTTPServer>(std::move(options));
std::vector<::proxygen::HTTPServer::IPConfig> ipconfig = {
{folly::SocketAddress("127.0.0.1", port_, true), ::proxygen::HTTPServer::Protocol::HTTP}};

server_->bind(ipconfig);
folly::Baton baton;
t_ = std::thread([this, &baton]() { this->server_->start([&baton]() { baton.post(); }); });
baton.wait();
}

void FakeHttpServer::stop() {
server_->stop();
}

void FakeHttpServer::join() {
t_.join();
}

} // namespace nebula
75 changes: 75 additions & 0 deletions src/mock/FakeHttpServer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/* Copyright (c) 2022 vesoft inc. All rights reserved.
*
* This source code is licensed under Apache 2.0 License.
*/

#ifndef MOCK_FAKEHTTPSERVER_H_
#define MOCK_FAKEHTTPSERVER_H_
#include <vector>

#include "proxygen/httpserver/HTTPServer.h"
#include "proxygen/httpserver/RequestHandler.h"
#include "proxygen/httpserver/RequestHandlerFactory.h"
namespace nebula {

class FakeHttpHandler : public proxygen::RequestHandler {
SuperYoko marked this conversation as resolved.
Show resolved Hide resolved
public:
void onRequest(std::unique_ptr<proxygen::HTTPMessage> headers) noexcept override;

void onBody(std::unique_ptr<folly::IOBuf> body) noexcept override;

void onEOM() noexcept override;

void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override;

void requestComplete() noexcept override;

void onError(proxygen::ProxygenError err) noexcept override;

private:
std::vector<std::pair<std::string, std::string>> headers_;
std::unique_ptr<folly::IOBuf> body_;
::proxygen::HTTPMethod method_;

virtual std::tuple<int, std::map<std::string, std::string>, std::string> onPut() {
return {200, {}, "PUT"};
}
virtual std::tuple<int, std::map<std::string, std::string>, std::string> onGet() {
return {200, {}, "GET"};
}
virtual std::tuple<int, std::map<std::string, std::string>, std::string> onDelete() {
return {200, {}, "DELETE"};
}
virtual std::tuple<int, std::map<std::string, std::string>, std::string> onPost() {
return {200, {}, "POST"};
}
};

class FakeHttpHandlerFactory : public ::proxygen::RequestHandlerFactory {
public:
void onServerStart(folly::EventBase*) noexcept override {}

void onServerStop() noexcept override {}

::proxygen::RequestHandler* onRequest(::proxygen::RequestHandler*,
::proxygen::HTTPMessage*) noexcept override {
return new FakeHttpHandler();
}
};

class FakeHttpServer {
public:
explicit FakeHttpServer(int port);
void start();
void stop();
void join();

private:
int port_;
std::thread t_;
std::unique_ptr<::proxygen::HTTPServer> server_ = nullptr;
};

} // namespace nebula

#endif