Skip to content

Commit 4f1fe76

Browse files
Http client ut (#4966)
* add fake http server * add http client ut * remove some useless code Co-authored-by: Sophie <84560950+Sophie-Xie@users.noreply.github.com>
1 parent c3048bc commit 4f1fe76

File tree

5 files changed

+220
-90
lines changed

5 files changed

+220
-90
lines changed

src/common/http/test/CMakeLists.txt

+2-10
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,10 @@ nebula_add_test(
1010
OBJECTS
1111
$<TARGET_OBJECTS:base_obj>
1212
$<TARGET_OBJECTS:http_client_obj>
13-
$<TARGET_OBJECTS:ws_obj>
14-
$<TARGET_OBJECTS:ws_common_obj>
15-
$<TARGET_OBJECTS:process_obj>
16-
$<TARGET_OBJECTS:fs_obj>
17-
$<TARGET_OBJECTS:stats_obj>
18-
$<TARGET_OBJECTS:time_obj>
19-
$<TARGET_OBJECTS:version_obj>
20-
$<TARGET_OBJECTS:datatypes_obj>
21-
$<TARGET_OBJECTS:wkt_wkb_io_obj>
13+
$<TARGET_OBJECTS:fake_http_server_obj>
2214
LIBRARIES
2315
${PROXYGEN_LIBRARIES}
2416
gtest
2517
curl
26-
18+
gtest_main
2719
)
+39-80
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,54 @@
1-
/* Copyright (c) 2019 vesoft inc. All rights reserved.
1+
/* Copyright (c) 2022 vesoft inc. All rights reserved.
22
*
33
* This source code is licensed under Apache 2.0 License.
44
*/
55

6-
#include <gtest/gtest.h>
7-
#include <proxygen/httpserver/RequestHandler.h>
8-
#include <proxygen/httpserver/ResponseBuilder.h>
9-
106
#include "common/http/HttpClient.h"
11-
#include "webservice/Common.h"
12-
#include "webservice/Router.h"
13-
#include "webservice/WebService.h"
7+
#include "gtest/gtest.h"
8+
#include "mock/FakeHttpServer.h"
149

1510
namespace nebula {
16-
namespace http {
17-
18-
class HttpClientHandler : public proxygen::RequestHandler {
19-
public:
20-
HttpClientHandler() = default;
21-
22-
void onRequest(std::unique_ptr<proxygen::HTTPMessage>) noexcept override {}
23-
24-
void onBody(std::unique_ptr<folly::IOBuf>) noexcept override {}
25-
26-
void onEOM() noexcept override {
27-
proxygen::ResponseBuilder(downstream_)
28-
.status(WebServiceUtils::to(HttpStatusCode::OK),
29-
WebServiceUtils::toString(HttpStatusCode::OK))
30-
.body("HttpClientHandler successfully")
31-
.sendWithEOM();
32-
}
33-
34-
void onUpgrade(proxygen::UpgradeProtocol) noexcept override {}
35-
36-
void requestComplete() noexcept override {
37-
delete this;
38-
}
3911

40-
void onError(proxygen::ProxygenError error) noexcept override {
41-
LOG(ERROR) << "HttpClientHandler Error: " << proxygen::getErrorString(error);
42-
}
43-
};
44-
class HttpClientTestEnv : public ::testing::Environment {
45-
public:
46-
void SetUp() override {
47-
FLAGS_ws_ip = "127.0.0.1";
48-
FLAGS_ws_http_port = 0;
49-
LOG(INFO) << "Starting web service...";
50-
webSvc_ = std::make_unique<WebService>();
12+
class HTTPClientTest : public ::testing::Test {};
5113

52-
auto& router = webSvc_->router();
53-
router.get("/path").handler([](auto&&) { return new HttpClientHandler(); });
54-
55-
auto status = webSvc_->start();
56-
ASSERT_TRUE(status.ok()) << status;
57-
}
14+
TEST_F(HTTPClientTest, GET) {
15+
FakeHttpServer server(3659);
16+
server.start();
17+
auto resp = HttpClient::get("http://localhost:3659");
18+
ASSERT_EQ(resp.curlCode, 0) << resp.curlMessage;
19+
ASSERT_EQ(resp.body, "GET");
20+
server.stop();
21+
server.join();
22+
}
5823

59-
void TearDown() override {
60-
webSvc_.reset();
61-
VLOG(1) << "Web service stopped";
62-
}
24+
TEST_F(HTTPClientTest, POST) {
25+
FakeHttpServer server(3660);
26+
server.start();
27+
auto resp = HttpClient::post("http://localhost:3660", {}, "");
28+
ASSERT_EQ(resp.curlCode, 0) << resp.curlMessage;
29+
ASSERT_EQ(resp.body, "POST");
30+
server.stop();
31+
server.join();
32+
}
6333

64-
private:
65-
std::unique_ptr<WebService> webSvc_;
66-
};
34+
TEST_F(HTTPClientTest, DELETE) {
35+
FakeHttpServer server(3661);
36+
server.start();
37+
auto resp = HttpClient::delete_("http://localhost:3661", {});
38+
ASSERT_EQ(resp.curlCode, 0) << resp.curlMessage;
39+
ASSERT_EQ(resp.body, "DELETE");
40+
server.stop();
41+
server.join();
42+
}
6743

68-
TEST(HttpClient, get) {
69-
{
70-
auto url =
71-
folly::stringPrintf("http://%s:%d%s", FLAGS_ws_ip.c_str(), FLAGS_ws_http_port, "/path");
72-
auto httpResp = HttpClient::get(url);
73-
ASSERT_EQ(httpResp.curlCode, 0);
74-
ASSERT_EQ("HttpClientHandler successfully", httpResp.body);
75-
}
76-
{
77-
auto url = folly::stringPrintf(
78-
"http://%s:%d%s", FLAGS_ws_ip.c_str(), FLAGS_ws_http_port, "/not_exist");
79-
auto httpResp = HttpClient::get(url);
80-
ASSERT_EQ(httpResp.curlCode, 0);
81-
ASSERT_TRUE(httpResp.body.empty());
82-
}
44+
TEST_F(HTTPClientTest, PUT) {
45+
FakeHttpServer server(3662);
46+
server.start();
47+
auto resp = HttpClient::put("http://localhost:3662", {}, "");
48+
ASSERT_EQ(resp.curlCode, 0) << resp.curlMessage;
49+
ASSERT_EQ(resp.body, "PUT");
50+
server.stop();
51+
server.join();
8352
}
8453

85-
} // namespace http
8654
} // namespace nebula
87-
88-
int main(int argc, char** argv) {
89-
testing::InitGoogleTest(&argc, argv);
90-
folly::init(&argc, &argv, true);
91-
google::SetStderrLogging(google::INFO);
92-
93-
::testing::AddGlobalTestEnvironment(new nebula::http::HttpClientTestEnv());
94-
return RUN_ALL_TESTS();
95-
}

src/mock/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,7 @@ nebula_add_library(
1111
)
1212

1313

14+
nebula_add_library(
15+
fake_http_server_obj OBJECT
16+
FakeHttpServer.cpp
17+
)

src/mock/FakeHttpServer.cpp

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/* Copyright (c) 2022 vesoft inc. All rights reserved.
2+
*
3+
* This source code is licensed under Apache 2.0 License.
4+
*/
5+
#include "mock/FakeHttpServer.h"
6+
7+
#include "folly/synchronization/Baton.h"
8+
#include "glog/logging.h"
9+
#include "proxygen/httpserver/HTTPServer.h"
10+
#include "proxygen/httpserver/HTTPServerOptions.h"
11+
#include "proxygen/httpserver/ResponseBuilder.h"
12+
13+
namespace nebula {
14+
15+
void FakeHttpHandler::onRequest(std::unique_ptr<proxygen::HTTPMessage> message) noexcept {
16+
CHECK(message->getMethod());
17+
method_ = message->getMethod().value();
18+
auto headers = message->extractHeaders();
19+
headers.forEach(
20+
[this](std::string name, std::string value) { this->headers_.emplace_back(name, value); });
21+
}
22+
23+
void FakeHttpHandler::onBody(std::unique_ptr<folly::IOBuf> buf) noexcept {
24+
if (body_) {
25+
body_->appendChain(std::move(buf));
26+
} else {
27+
body_ = std::move(buf);
28+
}
29+
}
30+
31+
void FakeHttpHandler::onEOM() noexcept {
32+
std::tuple<int, std::map<std::string, std::string>, std::string> result;
33+
switch (method_) {
34+
case ::proxygen::HTTPMethod::PUT:
35+
result = onPut();
36+
break;
37+
case ::proxygen::HTTPMethod::GET:
38+
result = onGet();
39+
break;
40+
case ::proxygen::HTTPMethod::POST:
41+
result = onPost();
42+
break;
43+
case ::proxygen::HTTPMethod::DELETE:
44+
result = onDelete();
45+
break;
46+
default:
47+
CHECK(false);
48+
break;
49+
}
50+
auto builder = ::proxygen::ResponseBuilder(downstream_);
51+
builder.status(std::get<0>(result), "");
52+
for (auto& [name, value] : std::get<1>(result)) {
53+
builder.header(name, value);
54+
}
55+
builder.body(std::get<2>(result));
56+
builder.sendWithEOM();
57+
}
58+
59+
void FakeHttpHandler::onUpgrade(proxygen::UpgradeProtocol) noexcept {
60+
// Do nothing
61+
}
62+
63+
void FakeHttpHandler::requestComplete() noexcept {
64+
delete this;
65+
}
66+
67+
void FakeHttpHandler::onError(proxygen::ProxygenError err) noexcept {
68+
LOG(FATAL) << ::proxygen::getErrorString(err);
69+
}
70+
71+
FakeHttpServer::FakeHttpServer(int port) : port_(port) {}
72+
73+
void FakeHttpServer::start() {
74+
::proxygen::HTTPServerOptions options;
75+
options.threads = 2;
76+
options.idleTimeout = std::chrono::milliseconds(60000);
77+
options.enableContentCompression = false;
78+
options.handlerFactories =
79+
proxygen::RequestHandlerChain().addThen<FakeHttpHandlerFactory>().build();
80+
options.h2cEnabled = true;
81+
82+
server_ = std::make_unique<::proxygen::HTTPServer>(std::move(options));
83+
std::vector<::proxygen::HTTPServer::IPConfig> ipconfig = {
84+
{folly::SocketAddress("127.0.0.1", port_, true), ::proxygen::HTTPServer::Protocol::HTTP}};
85+
86+
server_->bind(ipconfig);
87+
folly::Baton baton;
88+
t_ = std::thread([this, &baton]() { this->server_->start([&baton]() { baton.post(); }); });
89+
baton.wait();
90+
}
91+
92+
void FakeHttpServer::stop() {
93+
server_->stop();
94+
}
95+
96+
void FakeHttpServer::join() {
97+
t_.join();
98+
}
99+
100+
} // namespace nebula

src/mock/FakeHttpServer.h

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* Copyright (c) 2022 vesoft inc. All rights reserved.
2+
*
3+
* This source code is licensed under Apache 2.0 License.
4+
*/
5+
6+
#ifndef MOCK_FAKEHTTPSERVER_H_
7+
#define MOCK_FAKEHTTPSERVER_H_
8+
#include <vector>
9+
10+
#include "proxygen/httpserver/HTTPServer.h"
11+
#include "proxygen/httpserver/RequestHandler.h"
12+
#include "proxygen/httpserver/RequestHandlerFactory.h"
13+
namespace nebula {
14+
15+
class FakeHttpHandler : public proxygen::RequestHandler {
16+
public:
17+
void onRequest(std::unique_ptr<proxygen::HTTPMessage> headers) noexcept override;
18+
19+
void onBody(std::unique_ptr<folly::IOBuf> body) noexcept override;
20+
21+
void onEOM() noexcept override;
22+
23+
void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override;
24+
25+
void requestComplete() noexcept override;
26+
27+
void onError(proxygen::ProxygenError err) noexcept override;
28+
29+
private:
30+
std::vector<std::pair<std::string, std::string>> headers_;
31+
std::unique_ptr<folly::IOBuf> body_;
32+
::proxygen::HTTPMethod method_;
33+
34+
virtual std::tuple<int, std::map<std::string, std::string>, std::string> onPut() {
35+
return {200, {}, "PUT"};
36+
}
37+
virtual std::tuple<int, std::map<std::string, std::string>, std::string> onGet() {
38+
return {200, {}, "GET"};
39+
}
40+
virtual std::tuple<int, std::map<std::string, std::string>, std::string> onDelete() {
41+
return {200, {}, "DELETE"};
42+
}
43+
virtual std::tuple<int, std::map<std::string, std::string>, std::string> onPost() {
44+
return {200, {}, "POST"};
45+
}
46+
};
47+
48+
class FakeHttpHandlerFactory : public ::proxygen::RequestHandlerFactory {
49+
public:
50+
void onServerStart(folly::EventBase*) noexcept override {}
51+
52+
void onServerStop() noexcept override {}
53+
54+
::proxygen::RequestHandler* onRequest(::proxygen::RequestHandler*,
55+
::proxygen::HTTPMessage*) noexcept override {
56+
return new FakeHttpHandler();
57+
}
58+
};
59+
60+
class FakeHttpServer {
61+
public:
62+
explicit FakeHttpServer(int port);
63+
void start();
64+
void stop();
65+
void join();
66+
67+
private:
68+
int port_;
69+
std::thread t_;
70+
std::unique_ptr<::proxygen::HTTPServer> server_ = nullptr;
71+
};
72+
73+
} // namespace nebula
74+
75+
#endif

0 commit comments

Comments
 (0)