message_allocator_end2end_test.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. /*
  2. *
  3. * Copyright 2019 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. #include <algorithm>
  19. #include <atomic>
  20. #include <condition_variable>
  21. #include <functional>
  22. #include <memory>
  23. #include <mutex>
  24. #include <sstream>
  25. #include <thread>
  26. #include <google/protobuf/arena.h>
  27. #include <gtest/gtest.h>
  28. #include <grpc/impl/codegen/log.h>
  29. #include <grpcpp/channel.h>
  30. #include <grpcpp/client_context.h>
  31. #include <grpcpp/create_channel.h>
  32. #include <grpcpp/server.h>
  33. #include <grpcpp/server_builder.h>
  34. #include <grpcpp/server_context.h>
  35. #include <grpcpp/support/client_callback.h>
  36. #include <grpcpp/support/message_allocator.h>
  37. #include "src/core/lib/iomgr/iomgr.h"
  38. #include "src/proto/grpc/testing/echo.grpc.pb.h"
  39. #include "test/core/util/port.h"
  40. #include "test/core/util/test_config.h"
  41. #include "test/cpp/util/test_credentials_provider.h"
  42. namespace grpc {
  43. namespace testing {
  44. namespace {
  45. class CallbackTestServiceImpl : public EchoTestService::CallbackService {
  46. public:
  47. explicit CallbackTestServiceImpl() {}
  48. void SetAllocatorMutator(
  49. std::function<void(RpcAllocatorState* allocator_state,
  50. const EchoRequest* req, EchoResponse* resp)>
  51. mutator) {
  52. allocator_mutator_ = std::move(mutator);
  53. }
  54. ServerUnaryReactor* Echo(CallbackServerContext* context,
  55. const EchoRequest* request,
  56. EchoResponse* response) override {
  57. response->set_message(request->message());
  58. if (allocator_mutator_) {
  59. allocator_mutator_(context->GetRpcAllocatorState(), request, response);
  60. }
  61. auto* reactor = context->DefaultReactor();
  62. reactor->Finish(Status::OK);
  63. return reactor;
  64. }
  65. private:
  66. std::function<void(RpcAllocatorState* allocator_state, const EchoRequest* req,
  67. EchoResponse* resp)>
  68. allocator_mutator_;
  69. };
  70. enum class Protocol { INPROC, TCP };
  71. class TestScenario {
  72. public:
  73. TestScenario(Protocol protocol, const std::string& creds_type)
  74. : protocol(protocol), credentials_type(creds_type) {}
  75. void Log() const;
  76. Protocol protocol;
  77. const std::string credentials_type;
  78. };
  79. std::ostream& operator<<(std::ostream& out, const TestScenario& scenario) {
  80. return out << "TestScenario{protocol="
  81. << (scenario.protocol == Protocol::INPROC ? "INPROC" : "TCP")
  82. << "," << scenario.credentials_type << "}";
  83. }
  84. void TestScenario::Log() const {
  85. std::ostringstream out;
  86. out << *this;
  87. gpr_log(GPR_INFO, "%s", out.str().c_str());
  88. }
  89. class MessageAllocatorEnd2endTestBase
  90. : public ::testing::TestWithParam<TestScenario> {
  91. protected:
  92. MessageAllocatorEnd2endTestBase() { GetParam().Log(); }
  93. ~MessageAllocatorEnd2endTestBase() override = default;
  94. void CreateServer(MessageAllocator<EchoRequest, EchoResponse>* allocator) {
  95. ServerBuilder builder;
  96. auto server_creds = GetCredentialsProvider()->GetServerCredentials(
  97. GetParam().credentials_type);
  98. if (GetParam().protocol == Protocol::TCP) {
  99. picked_port_ = grpc_pick_unused_port_or_die();
  100. server_address_ << "localhost:" << picked_port_;
  101. builder.AddListeningPort(server_address_.str(), server_creds);
  102. }
  103. callback_service_.SetMessageAllocatorFor_Echo(allocator);
  104. builder.RegisterService(&callback_service_);
  105. server_ = builder.BuildAndStart();
  106. }
  107. void DestroyServer() {
  108. if (server_) {
  109. server_->Shutdown();
  110. server_.reset();
  111. }
  112. }
  113. void ResetStub() {
  114. ChannelArguments args;
  115. auto channel_creds = GetCredentialsProvider()->GetChannelCredentials(
  116. GetParam().credentials_type, &args);
  117. switch (GetParam().protocol) {
  118. case Protocol::TCP:
  119. channel_ = grpc::CreateCustomChannel(server_address_.str(),
  120. channel_creds, args);
  121. break;
  122. case Protocol::INPROC:
  123. channel_ = server_->InProcessChannel(args);
  124. break;
  125. default:
  126. assert(false);
  127. }
  128. stub_ = EchoTestService::NewStub(channel_);
  129. }
  130. void TearDown() override {
  131. DestroyServer();
  132. if (picked_port_ > 0) {
  133. grpc_recycle_unused_port(picked_port_);
  134. }
  135. }
  136. void SendRpcs(int num_rpcs) {
  137. std::string test_string("");
  138. for (int i = 0; i < num_rpcs; i++) {
  139. EchoRequest request;
  140. EchoResponse response;
  141. ClientContext cli_ctx;
  142. test_string += std::string(1024, 'x');
  143. request.set_message(test_string);
  144. std::string val;
  145. cli_ctx.set_compression_algorithm(GRPC_COMPRESS_GZIP);
  146. std::mutex mu;
  147. std::condition_variable cv;
  148. bool done = false;
  149. stub_->async()->Echo(
  150. &cli_ctx, &request, &response,
  151. [&request, &response, &done, &mu, &cv, val](Status s) {
  152. GPR_ASSERT(s.ok());
  153. EXPECT_EQ(request.message(), response.message());
  154. std::lock_guard<std::mutex> l(mu);
  155. done = true;
  156. cv.notify_one();
  157. });
  158. std::unique_lock<std::mutex> l(mu);
  159. while (!done) {
  160. cv.wait(l);
  161. }
  162. }
  163. }
  164. int picked_port_{0};
  165. std::shared_ptr<Channel> channel_;
  166. std::unique_ptr<EchoTestService::Stub> stub_;
  167. CallbackTestServiceImpl callback_service_;
  168. std::unique_ptr<Server> server_;
  169. std::ostringstream server_address_;
  170. };
  171. class NullAllocatorTest : public MessageAllocatorEnd2endTestBase {};
  172. TEST_P(NullAllocatorTest, SimpleRpc) {
  173. CreateServer(nullptr);
  174. ResetStub();
  175. SendRpcs(1);
  176. }
  177. class SimpleAllocatorTest : public MessageAllocatorEnd2endTestBase {
  178. public:
  179. class SimpleAllocator : public MessageAllocator<EchoRequest, EchoResponse> {
  180. public:
  181. class MessageHolderImpl : public MessageHolder<EchoRequest, EchoResponse> {
  182. public:
  183. MessageHolderImpl(std::atomic_int* request_deallocation_count,
  184. std::atomic_int* messages_deallocation_count)
  185. : request_deallocation_count_(request_deallocation_count),
  186. messages_deallocation_count_(messages_deallocation_count) {
  187. set_request(new EchoRequest);
  188. set_response(new EchoResponse);
  189. }
  190. void Release() override {
  191. (*messages_deallocation_count_)++;
  192. delete request();
  193. delete response();
  194. delete this;
  195. }
  196. void FreeRequest() override {
  197. (*request_deallocation_count_)++;
  198. delete request();
  199. set_request(nullptr);
  200. }
  201. EchoRequest* ReleaseRequest() {
  202. auto* ret = request();
  203. set_request(nullptr);
  204. return ret;
  205. }
  206. private:
  207. std::atomic_int* const request_deallocation_count_;
  208. std::atomic_int* const messages_deallocation_count_;
  209. };
  210. MessageHolder<EchoRequest, EchoResponse>* AllocateMessages() override {
  211. allocation_count++;
  212. return new MessageHolderImpl(&request_deallocation_count,
  213. &messages_deallocation_count);
  214. }
  215. int allocation_count = 0;
  216. std::atomic_int request_deallocation_count{0};
  217. std::atomic_int messages_deallocation_count{0};
  218. };
  219. };
  220. TEST_P(SimpleAllocatorTest, SimpleRpc) {
  221. const int kRpcCount = 10;
  222. std::unique_ptr<SimpleAllocator> allocator(new SimpleAllocator);
  223. CreateServer(allocator.get());
  224. ResetStub();
  225. SendRpcs(kRpcCount);
  226. // messages_deallocaton_count is updated in Release after server side OnDone.
  227. // Destroy server to make sure it has been updated.
  228. DestroyServer();
  229. EXPECT_EQ(kRpcCount, allocator->allocation_count);
  230. EXPECT_EQ(kRpcCount, allocator->messages_deallocation_count);
  231. EXPECT_EQ(0, allocator->request_deallocation_count);
  232. }
  233. TEST_P(SimpleAllocatorTest, RpcWithEarlyFreeRequest) {
  234. const int kRpcCount = 10;
  235. std::unique_ptr<SimpleAllocator> allocator(new SimpleAllocator);
  236. auto mutator = [](RpcAllocatorState* allocator_state, const EchoRequest* req,
  237. EchoResponse* resp) {
  238. auto* info =
  239. static_cast<SimpleAllocator::MessageHolderImpl*>(allocator_state);
  240. EXPECT_EQ(req, info->request());
  241. EXPECT_EQ(resp, info->response());
  242. allocator_state->FreeRequest();
  243. EXPECT_EQ(nullptr, info->request());
  244. };
  245. callback_service_.SetAllocatorMutator(mutator);
  246. CreateServer(allocator.get());
  247. ResetStub();
  248. SendRpcs(kRpcCount);
  249. // messages_deallocaton_count is updated in Release after server side OnDone.
  250. // Destroy server to make sure it has been updated.
  251. DestroyServer();
  252. EXPECT_EQ(kRpcCount, allocator->allocation_count);
  253. EXPECT_EQ(kRpcCount, allocator->messages_deallocation_count);
  254. EXPECT_EQ(kRpcCount, allocator->request_deallocation_count);
  255. }
  256. TEST_P(SimpleAllocatorTest, RpcWithReleaseRequest) {
  257. const int kRpcCount = 10;
  258. std::unique_ptr<SimpleAllocator> allocator(new SimpleAllocator);
  259. std::vector<EchoRequest*> released_requests;
  260. auto mutator = [&released_requests](RpcAllocatorState* allocator_state,
  261. const EchoRequest* req,
  262. EchoResponse* resp) {
  263. auto* info =
  264. static_cast<SimpleAllocator::MessageHolderImpl*>(allocator_state);
  265. EXPECT_EQ(req, info->request());
  266. EXPECT_EQ(resp, info->response());
  267. released_requests.push_back(info->ReleaseRequest());
  268. EXPECT_EQ(nullptr, info->request());
  269. };
  270. callback_service_.SetAllocatorMutator(mutator);
  271. CreateServer(allocator.get());
  272. ResetStub();
  273. SendRpcs(kRpcCount);
  274. // messages_deallocaton_count is updated in Release after server side OnDone.
  275. // Destroy server to make sure it has been updated.
  276. DestroyServer();
  277. EXPECT_EQ(kRpcCount, allocator->allocation_count);
  278. EXPECT_EQ(kRpcCount, allocator->messages_deallocation_count);
  279. EXPECT_EQ(0, allocator->request_deallocation_count);
  280. EXPECT_EQ(static_cast<unsigned>(kRpcCount), released_requests.size());
  281. for (auto* req : released_requests) {
  282. delete req;
  283. }
  284. }
  285. class ArenaAllocatorTest : public MessageAllocatorEnd2endTestBase {
  286. public:
  287. class ArenaAllocator : public MessageAllocator<EchoRequest, EchoResponse> {
  288. public:
  289. class MessageHolderImpl : public MessageHolder<EchoRequest, EchoResponse> {
  290. public:
  291. MessageHolderImpl() {
  292. set_request(
  293. google::protobuf::Arena::CreateMessage<EchoRequest>(&arena_));
  294. set_response(
  295. google::protobuf::Arena::CreateMessage<EchoResponse>(&arena_));
  296. }
  297. void Release() override { delete this; }
  298. void FreeRequest() override { GPR_ASSERT(0); }
  299. private:
  300. google::protobuf::Arena arena_;
  301. };
  302. MessageHolder<EchoRequest, EchoResponse>* AllocateMessages() override {
  303. allocation_count++;
  304. return new MessageHolderImpl;
  305. }
  306. int allocation_count = 0;
  307. };
  308. };
  309. TEST_P(ArenaAllocatorTest, SimpleRpc) {
  310. const int kRpcCount = 10;
  311. std::unique_ptr<ArenaAllocator> allocator(new ArenaAllocator);
  312. CreateServer(allocator.get());
  313. ResetStub();
  314. SendRpcs(kRpcCount);
  315. EXPECT_EQ(kRpcCount, allocator->allocation_count);
  316. }
  317. std::vector<TestScenario> CreateTestScenarios(bool test_insecure) {
  318. std::vector<TestScenario> scenarios;
  319. std::vector<std::string> credentials_types{
  320. GetCredentialsProvider()->GetSecureCredentialsTypeList()};
  321. auto insec_ok = [] {
  322. // Only allow insecure credentials type when it is registered with the
  323. // provider. User may create providers that do not have insecure.
  324. return GetCredentialsProvider()->GetChannelCredentials(
  325. kInsecureCredentialsType, nullptr) != nullptr;
  326. };
  327. if (test_insecure && insec_ok()) {
  328. credentials_types.push_back(kInsecureCredentialsType);
  329. }
  330. GPR_ASSERT(!credentials_types.empty());
  331. Protocol parr[]{Protocol::INPROC, Protocol::TCP};
  332. for (Protocol p : parr) {
  333. for (const auto& cred : credentials_types) {
  334. // TODO(vjpai): Test inproc with secure credentials when feasible
  335. if (p == Protocol::INPROC &&
  336. (cred != kInsecureCredentialsType || !insec_ok())) {
  337. continue;
  338. }
  339. scenarios.emplace_back(p, cred);
  340. }
  341. }
  342. return scenarios;
  343. }
  344. INSTANTIATE_TEST_SUITE_P(NullAllocatorTest, NullAllocatorTest,
  345. ::testing::ValuesIn(CreateTestScenarios(true)));
  346. INSTANTIATE_TEST_SUITE_P(SimpleAllocatorTest, SimpleAllocatorTest,
  347. ::testing::ValuesIn(CreateTestScenarios(true)));
  348. INSTANTIATE_TEST_SUITE_P(ArenaAllocatorTest, ArenaAllocatorTest,
  349. ::testing::ValuesIn(CreateTestScenarios(true)));
  350. } // namespace
  351. } // namespace testing
  352. } // namespace grpc
  353. int main(int argc, char** argv) {
  354. grpc::testing::TestEnvironment env(argc, argv);
  355. ::testing::InitGoogleTest(&argc, argv);
  356. int ret = RUN_ALL_TESTS();
  357. return ret;
  358. }