Skip to content

Commit

Permalink
Add unit test for client response movability
Browse files Browse the repository at this point in the history
  • Loading branch information
Ravi Nagarjun Akella authored and Ravi Nagarjun Akella committed Feb 8, 2024
1 parent 2426064 commit ad398da
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 29 deletions.
1 change: 1 addition & 0 deletions include/sisl/grpc/rpc_client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ class GenericClientResponse {
~GenericClientResponse();

io_blob& response_blob();
grpc::ByteBuffer response_buf();

private:
grpc::ByteBuffer m_response_buf;
Expand Down
11 changes: 6 additions & 5 deletions src/grpc/rpc_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,17 +188,16 @@ std::unique_ptr< GrpcAsyncClient::GenericAsyncStub > GrpcAsyncClient::make_gener
GenericClientResponse::GenericClientResponse(grpc::ByteBuffer const& buf) : m_response_buf(buf) {}

GenericClientResponse::GenericClientResponse(GenericClientResponse&& other) :
m_response_buf(other.m_response_buf),
m_response_blob(other.m_response_blob),
m_response_blob_allocated(other.m_response_blob_allocated) {
m_response_blob(other.m_response_blob), m_response_blob_allocated(other.m_response_blob_allocated) {
m_response_buf.Swap(&(other.m_response_buf));
other.m_response_blob.set_bytes(static_cast< uint8_t* >(nullptr));
other.m_response_blob.set_size(0);
}

GenericClientResponse& GenericClientResponse::operator=(GenericClientResponse&& other) {
if (m_response_blob_allocated) { m_response_blob.buf_free(); }
m_response_buf = other.m_response_buf;
m_response_blob = other.m_response_blob;
m_response_buf.Clear();
m_response_buf.Swap(&(other.m_response_buf));
m_response_blob_allocated = other.m_response_blob_allocated;
other.m_response_blob.set_bytes(static_cast< uint8_t* >(nullptr));
other.m_response_blob.set_size(0);
Expand All @@ -210,6 +209,8 @@ GenericClientResponse::~GenericClientResponse() {
if (m_response_blob_allocated) { m_response_blob.buf_free(); }
}

grpc::ByteBuffer GenericClientResponse::response_buf() { return m_response_buf; }

io_blob& GenericClientResponse::response_blob() {
if (m_response_blob.cbytes() == nullptr) {
if (auto status = try_deserialize_from_byte_buffer(m_response_buf, m_response_blob);
Expand Down
11 changes: 11 additions & 0 deletions src/grpc/tests/unit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,14 @@ target_link_libraries(auth_test
${COMMON_DEPS}
)
add_test(NAME Auth_Test COMMAND auth_test)

add_executable(client_test
client_test.cpp
)
target_link_libraries(client_test
sisl
sisl_grpc
GTest::gmock
${COMMON_DEPS}
)
add_test(NAME Client_Test COMMAND client_test)
40 changes: 18 additions & 22 deletions src/grpc/tests/unit/auth_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,34 +356,34 @@ TEST(GenericServiceDeathTest, basic_test) {
auto g_grpc_server = GrpcServer::make("0.0.0.0:56789", nullptr, 1, "", "");
// register rpc before generic service is registered
#ifndef NDEBUG
ASSERT_DEATH(g_grpc_server->register_generic_rpc(
"method1", [](boost::intrusive_ptr< GenericRpcData >&) { return true; }),
"Assertion .* failed");
ASSERT_DEATH(
g_grpc_server->register_generic_rpc("method1", [](boost::intrusive_ptr< GenericRpcData >&) { return true; }),
"Assertion .* failed");
#else
EXPECT_FALSE(g_grpc_server->register_generic_rpc(
"method1", [](boost::intrusive_ptr< GenericRpcData >&) { return true; }));
EXPECT_FALSE(
g_grpc_server->register_generic_rpc("method1", [](boost::intrusive_ptr< GenericRpcData >&) { return true; }));
#endif

ASSERT_TRUE(g_grpc_server->register_async_generic_service());
// duplicate register
EXPECT_FALSE(g_grpc_server->register_async_generic_service());
// register rpc before server is run
#ifndef NDEBUG
ASSERT_DEATH(g_grpc_server->register_generic_rpc(
"method1", [](boost::intrusive_ptr< GenericRpcData >&) { return true; }),
"Assertion .* failed");
ASSERT_DEATH(
g_grpc_server->register_generic_rpc("method1", [](boost::intrusive_ptr< GenericRpcData >&) { return true; }),
"Assertion .* failed");
#else
EXPECT_FALSE(g_grpc_server->register_generic_rpc(
"method1", [](boost::intrusive_ptr< GenericRpcData >&) { return true; }));
EXPECT_FALSE(
g_grpc_server->register_generic_rpc("method1", [](boost::intrusive_ptr< GenericRpcData >&) { return true; }));
#endif
g_grpc_server->run();
EXPECT_TRUE(g_grpc_server->register_generic_rpc(
"method1", [](boost::intrusive_ptr< GenericRpcData >&) { return true; }));
EXPECT_TRUE(g_grpc_server->register_generic_rpc(
"method2", [](boost::intrusive_ptr< GenericRpcData >&) { return true; }));
EXPECT_TRUE(
g_grpc_server->register_generic_rpc("method1", [](boost::intrusive_ptr< GenericRpcData >&) { return true; }));
EXPECT_TRUE(
g_grpc_server->register_generic_rpc("method2", [](boost::intrusive_ptr< GenericRpcData >&) { return true; }));
// re-register method 1
EXPECT_FALSE(g_grpc_server->register_generic_rpc(
"method1", [](boost::intrusive_ptr< GenericRpcData >&) { return true; }));
EXPECT_FALSE(
g_grpc_server->register_generic_rpc("method1", [](boost::intrusive_ptr< GenericRpcData >&) { return true; }));

auto client = std::make_unique< GrpcAsyncClient >("0.0.0.0:56789", "", "");
client->init();
Expand All @@ -392,15 +392,11 @@ TEST(GenericServiceDeathTest, basic_test) {
::grpc::ByteBuffer cli_buf;
generic_stub->call_unary(
cli_buf, "method1",
[method = "method1"](::grpc::ByteBuffer&, ::grpc::Status& status) {
validate_generic_reply(method, status);
},
[method = "method1"](::grpc::ByteBuffer&, ::grpc::Status& status) { validate_generic_reply(method, status); },
1);
generic_stub->call_unary(
cli_buf, "method2",
[method = "method2"](::grpc::ByteBuffer&, ::grpc::Status& status) {
validate_generic_reply(method, status);
},
[method = "method2"](::grpc::ByteBuffer&, ::grpc::Status& status) { validate_generic_reply(method, status); },
1);
generic_stub->call_unary(
cli_buf, "method_unknown",
Expand Down
75 changes: 75 additions & 0 deletions src/grpc/tests/unit/client_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <sisl/logging/logging.h>
#include <sisl/options/options.h>

#include "sisl/grpc/rpc_client.hpp"

SISL_LOGGING_INIT(grpc_server)
SISL_OPTIONS_ENABLE(logging)

namespace sisltesting {
using namespace sisl;
using namespace ::grpc;

static void SerializeToByteBuffer(ByteBuffer& buffer, std::string const& msg) {
buffer.Clear();
Slice slice(msg);
ByteBuffer tmp(&slice, 1);
buffer.Swap(&tmp);
}

static std::string DeserializeFromBuffer(ByteBuffer const& buffer) {
std::vector< grpc::Slice > slices;
(void)buffer.Dump(&slices);
std::string buf;
buf.reserve(buffer.Length());
for (auto s = slices.begin(); s != slices.end(); s++) {
buf.append(reinterpret_cast< const char* >(s->begin()), s->size());
}
return buf;
}

TEST(GenericClientResponseTest, movability_test) {
std::string msg("Hello");
ByteBuffer buffer;
SerializeToByteBuffer(buffer, msg);
GenericClientResponse resp1(buffer);
auto& b1 = resp1.response_blob();
auto buf1 = resp1.response_buf();
EXPECT_EQ(msg, DeserializeFromBuffer(buf1));
EXPECT_EQ(msg, std::string(reinterpret_cast< const char* >(b1.cbytes()), b1.size()));

// move construction
GenericClientResponse resp2(std::move(resp1));
auto& b2 = resp2.response_blob();
EXPECT_EQ(msg, std::string(b2.bytes(), b2.bytes() + b2.size()));
EXPECT_TRUE(resp2.response_buf().Valid());
EXPECT_EQ(b1.size(), 0);
EXPECT_EQ(b1.bytes(), nullptr);
EXPECT_FALSE(resp1.response_buf().Valid());
EXPECT_EQ(resp1.response_blob().size(), 0);
EXPECT_EQ(resp1.response_blob().bytes(), nullptr);

// move assignment
GenericClientResponse resp3 = std::move(resp2);
auto b3 = resp3.response_blob();
EXPECT_EQ(msg, std::string(b3.bytes(), b3.bytes() + b3.size()));
EXPECT_TRUE(resp3.response_buf().Valid());
EXPECT_EQ(b2.size(), 0);
EXPECT_EQ(b2.bytes(), nullptr);
EXPECT_FALSE(resp2.response_buf().Valid());
EXPECT_EQ(resp2.response_blob().size(), 0);
EXPECT_EQ(resp2.response_blob().bytes(), nullptr);
}

} // namespace sisltesting

int main(int argc, char* argv[]) {
::testing::InitGoogleMock(&argc, argv);
SISL_OPTIONS_LOAD(argc, argv, logging)
sisl::logging::SetLogger("auth_test");
int ret{RUN_ALL_TESTS()};
sisl::GrpcAsyncClientWorker::shutdown_all();
return ret;
}
12 changes: 10 additions & 2 deletions src/grpc/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,16 @@ namespace sisl {
grpc::Slice slice;
auto status = cli_byte_buf.TrySingleSlice(&slice);
if (status.ok()) {
cli_buf.set_bytes(slice.begin());
cli_buf.set_size(slice.size());
// if slice is inlined, we can not use the reference to the slice
auto raw_slice = slice.c_slice();
if ((raw_slice).refcount) {
cli_buf.set_bytes(slice.begin());
cli_buf.set_size(slice.size());
} else {
status = grpc::Status(grpc::StatusCode::FAILED_PRECONDITION,
"Inlined slice, can not use the reference to the slice.");
}
grpc_slice_unref(raw_slice);
}
return status;
}
Expand Down

0 comments on commit ad398da

Please sign in to comment.