Skip to content

Commit 1f008b8

Browse files
committed
add demo with cpp-httplib
1 parent 5c4d0d1 commit 1f008b8

File tree

4 files changed

+108
-26
lines changed

4 files changed

+108
-26
lines changed

src/iceberg/catalog/rest/rest_catalog.cc

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,23 @@
1919

2020
#include "iceberg/catalog/rest/rest_catalog.h"
2121

22+
#include <utility>
23+
2224
#include <cpr/cpr.h>
2325

2426
namespace iceberg::catalog::rest {
2527

2628
RestCatalog::RestCatalog(const std::string& base_url) : base_url_(std::move(base_url)) {}
2729

28-
cpr::Response RestCatalog::testCprIntegration() {
29-
// Simple GET request demo
30-
cpr::Response r =
31-
cpr::Get(cpr::Url{"https://httpbin.org/get"}, cpr::Parameters{{"hello", "world"}});
30+
cpr::Response RestCatalog::GetConfig() {
31+
cpr::Url url = cpr::Url{base_url_ + "/v1/config"};
32+
cpr::Response r = cpr::Get(url);
33+
return r;
34+
}
3235

36+
cpr::Response RestCatalog::ListNamespaces() {
37+
cpr::Url url = cpr::Url{base_url_ + "/v1/namespaces"};
38+
cpr::Response r = cpr::Get(url);
3339
return r;
3440
}
3541

src/iceberg/catalog/rest/rest_catalog.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
#include <string>
2121

22-
#include "cpr/response.h"
22+
#include <cpr/cpr.h>
2323

2424
namespace iceberg::catalog::rest {
2525

@@ -28,7 +28,9 @@ class RestCatalog {
2828
explicit RestCatalog(const std::string& base_url);
2929
~RestCatalog() = default;
3030

31-
cpr::Response testCprIntegration();
31+
cpr::Response GetConfig();
32+
33+
cpr::Response ListNamespaces();
3234

3335
private:
3436
std::string base_url_;

test/CMakeLists.txt

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,23 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717

18+
fetchcontent_declare(cpp-httplib
19+
GIT_REPOSITORY https://github.com/yhirose/cpp-httplib.git
20+
GIT_TAG 89c932f313c6437c38f2982869beacc89c2f2246 #release-0.26.0
21+
)
22+
1823
fetchcontent_declare(googletest
1924
GIT_REPOSITORY https://github.com/google/googletest.git
2025
GIT_TAG b514bdc898e2951020cbdca1304b75f5950d1f59 # release-1.15.2
2126
FIND_PACKAGE_ARGS
2227
NAMES
2328
GTest)
24-
fetchcontent_makeavailable(googletest)
29+
30+
if(ICEBERG_BUILD_REST_CATALOG)
31+
fetchcontent_makeavailable(cpp-httplib googletest)
32+
else()
33+
fetchcontent_makeavailable(googletest)
34+
endif()
2535

2636
set(ICEBERG_TEST_RESOURCES "${CMAKE_SOURCE_DIR}/test/resources")
2737

@@ -129,4 +139,12 @@ endif()
129139
if(ICEBERG_BUILD_REST_CATALOG)
130140
add_iceberg_test(rest_catalog_test SOURCES rest_catalog_test.cc)
131141
target_link_libraries(rest_catalog_test PRIVATE iceberg_rest_catalog_static)
142+
target_include_directories(rest_catalog_test PRIVATE ${cpp-httplib_SOURCE_DIR})
143+
144+
if(WIN32)
145+
target_link_libraries(rest_catalog_test PRIVATE ws2_32 crypt32)
146+
else()
147+
target_link_libraries(rest_catalog_test PRIVATE Threads::Threads)
148+
endif()
149+
132150
endif()

test/rest_catalog_test.cc

Lines changed: 75 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,37 +19,93 @@
1919

2020
#include "iceberg/catalog/rest/rest_catalog.h"
2121

22+
#include <httplib.h>
23+
24+
#include <memory>
25+
#include <thread>
26+
2227
#include <gmock/gmock.h>
2328
#include <gtest/gtest.h>
24-
25-
#include "cpr/error.h"
26-
#include "cpr/response.h"
29+
#include <nlohmann/json.hpp>
2730

2831
namespace iceberg::catalog::rest {
2932

30-
class RestCatalogTest : public ::testing::Test {};
33+
class RestCatalogIntegrationTest : public ::testing::Test {
34+
protected:
35+
void SetUp() override {
36+
server_ = std::make_unique<httplib::Server>();
37+
port_ = server_->bind_to_any_port("127.0.0.1");
3138

32-
TEST_F(RestCatalogTest, CanCreateRestCatalog) {
33-
RestCatalog catalog("http://localhost:8181");
34-
SUCCEED();
35-
}
39+
server_thread_ = std::thread([this]() { server_->listen_after_bind(); });
40+
}
41+
42+
void TearDown() override {
43+
server_->stop();
44+
if (server_thread_.joinable()) {
45+
server_thread_.join();
46+
}
47+
}
48+
49+
std::unique_ptr<httplib::Server> server_;
50+
int port_ = -1;
51+
std::thread server_thread_;
52+
};
53+
54+
TEST_F(RestCatalogIntegrationTest, GetConfigSuccessfully) {
55+
server_->Get("/v1/config", [](const httplib::Request&, httplib::Response& res) {
56+
res.status = 200;
57+
res.set_content(R"({"warehouse": "s3://test-bucket"})", "application/json");
58+
});
3659

37-
TEST_F(RestCatalogTest, MultipleCatalogInstances) {
38-
RestCatalog catalog1("http://localhost:8181");
39-
RestCatalog catalog2("http://localhost:8182");
40-
SUCCEED();
60+
std::string base_uri = "http://127.0.0.1:" + std::to_string(port_);
61+
RestCatalog catalog(base_uri);
62+
cpr::Response response = catalog.GetConfig();
63+
64+
ASSERT_EQ(response.error.code, cpr::ErrorCode::OK);
65+
ASSERT_EQ(response.status_code, 200);
66+
67+
auto json_body = nlohmann::json::parse(response.text);
68+
EXPECT_EQ(json_body["warehouse"], "s3://test-bucket");
4169
}
4270

43-
TEST_F(RestCatalogTest, TestCprIntegration) {
44-
RestCatalog catalog("http://localhost:8181");
71+
TEST_F(RestCatalogIntegrationTest, ListNamespacesReturnsMultipleResults) {
72+
server_->Get("/v1/namespaces", [](const httplib::Request&, httplib::Response& res) {
73+
res.status = 200;
74+
res.set_content(R"({
75+
"namespaces": [
76+
["accounting", "db"],
77+
["production", "db"]
78+
]
79+
})",
80+
"application/json");
81+
});
82+
83+
std::string base_uri = "http://127.0.0.1:" + std::to_string(port_);
84+
RestCatalog catalog(base_uri);
85+
cpr::Response response = catalog.ListNamespaces();
86+
87+
ASSERT_EQ(response.error.code, cpr::ErrorCode::OK);
88+
ASSERT_EQ(response.status_code, 200);
89+
90+
auto json_body = nlohmann::json::parse(response.text);
91+
ASSERT_TRUE(json_body.contains("namespaces"));
92+
EXPECT_EQ(json_body["namespaces"].size(), 2);
93+
EXPECT_THAT(json_body["namespaces"][0][0], "accounting");
94+
}
4595

46-
cpr::Response response = catalog.testCprIntegration();
96+
TEST_F(RestCatalogIntegrationTest, HandlesServerError) {
97+
server_->Get("/v1/config", [](const httplib::Request&, httplib::Response& res) {
98+
res.status = 500;
99+
res.set_content("Internal Server Error", "text/plain");
100+
});
47101

48-
ASSERT_EQ(response.error.code, cpr::ErrorCode::OK)
49-
<< "CPR transport error: " << response.error.message;
102+
std::string base_uri = "http://127.0.0.1:" + std::to_string(port_);
103+
RestCatalog catalog(base_uri);
104+
cpr::Response response = catalog.GetConfig();
50105

51-
EXPECT_EQ(response.status_code, 200);
52-
EXPECT_THAT(response.text, ::testing::HasSubstr("\"hello\": \"world\""));
106+
ASSERT_EQ(response.error.code, cpr::ErrorCode::OK);
107+
ASSERT_EQ(response.status_code, 500);
108+
ASSERT_EQ(response.text, "Internal Server Error");
53109
}
54110

55111
} // namespace iceberg::catalog::rest

0 commit comments

Comments
 (0)