From a27eb1d07a78ae5115b0251b1096811722a8174d Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Wed, 28 Sep 2016 12:19:52 -0700 Subject: [PATCH 01/14] added the unimplemented_call test to interop_client.cc. Next step is to call this from the driver program, run_interop_tests.py --- src/proto/grpc/testing/test.proto | 3 +++ test/cpp/interop/client.cc | 9 +++++++-- test/cpp/interop/interop_client.cc | 20 ++++++++++++++++++++ test/cpp/interop/interop_client.h | 1 + 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/proto/grpc/testing/test.proto b/src/proto/grpc/testing/test.proto index 84369db4b8a..084d59f8aaf 100644 --- a/src/proto/grpc/testing/test.proto +++ b/src/proto/grpc/testing/test.proto @@ -69,6 +69,9 @@ service TestService { // first request. rpc HalfDuplexCall(stream StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse); + + // A call that no server should implement + rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty); } // A simple service NOT implemented at servers so clients can test for diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc index 032b378b1a1..51de7ac8828 100644 --- a/test/cpp/interop/client.cc +++ b/test/cpp/interop/client.cc @@ -79,7 +79,8 @@ DEFINE_string(test_case, "large_unary", "slow_consumer : single request with response streaming with " "slow client consumer;\n" "status_code_and_message: verify status code & message;\n" - "timeout_on_sleeping_server: deadline exceeds on stream;\n"); + "timeout_on_sleeping_server: deadline exceeds on stream;\n" + "unimplemented_method: client calls an unimplemented_method;\n"); DEFINE_string(default_service_account, "", "Email of GCE default service account"); DEFINE_string(service_account_key_file, "", @@ -149,6 +150,8 @@ int main(int argc, char** argv) { client.DoStatusWithMessage(); } else if (FLAGS_test_case == "custom_metadata") { client.DoCustomMetadata(); + } else if (FLAGS_test_case == "unimplemented_method") { + client.DoUnimplementedMethod(); } else if (FLAGS_test_case == "all") { client.DoEmpty(); client.DoLargeUnary(); @@ -166,6 +169,7 @@ int main(int argc, char** argv) { client.DoEmptyStream(); client.DoStatusWithMessage(); client.DoCustomMetadata(); + client.DoUnimplementedMethod(); // service_account_creds and jwt_token_creds can only run with ssl. if (FLAGS_use_tls) { grpc::string json_key = GetServiceAccountJsonKey(); @@ -198,7 +202,8 @@ int main(int argc, char** argv) { "server_compressed_unary", "server_streaming", "status_code_and_message", - "timeout_on_sleeping_server"}; + "timeout_on_sleeping_server", + "unimplemented_method"}; char* joined_testcases = gpr_strjoin_sep(testcases, GPR_ARRAY_SIZE(testcases), "\n", NULL); diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc index 6117878a33f..b43f166b96c 100644 --- a/test/cpp/interop/interop_client.cc +++ b/test/cpp/interop/interop_client.cc @@ -937,5 +937,25 @@ bool InteropClient::DoCustomMetadata() { return true; } +bool InteropClient::DoUnimplementedMethod() { + gpr_log(GPR_DEBUG, "Sending a request for an unimplemented rpc..."); + + Empty request = Empty::default_instance(); + Empty response = Empty::default_instance(); + ClientContext context; + + gpr_log(GPR_DEBUG, "here"); + + Status s = serviceStub_.Get()->UnimplementedCall( + &context, request, &response); + + if (!AssertStatusCode(s, StatusCode::UNIMPLEMENTED)) { + return false; + } + + gpr_log(GPR_DEBUG, "unimplemented rpc done."); + return true; +} + } // namespace testing } // namespace grpc diff --git a/test/cpp/interop/interop_client.h b/test/cpp/interop/interop_client.h index eb886fcb7e2..a535bf9a5a5 100644 --- a/test/cpp/interop/interop_client.h +++ b/test/cpp/interop/interop_client.h @@ -79,6 +79,7 @@ class InteropClient { bool DoEmptyStream(); bool DoStatusWithMessage(); bool DoCustomMetadata(); + bool DoUnimplementedMethod(); // Auth tests. // username is a string containing the user email bool DoJwtTokenCreds(const grpc::string& username); From 02e70ed120120b95f35862d5af8988ec18812ca6 Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Wed, 28 Sep 2016 14:17:25 -0700 Subject: [PATCH 02/14] changed method name in test.proto to more accurately reflect how the calls will be used --- src/proto/grpc/testing/test.proto | 5 +++-- test/cpp/interop/interop_client.cc | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/proto/grpc/testing/test.proto b/src/proto/grpc/testing/test.proto index 084d59f8aaf..801baf8b3b2 100644 --- a/src/proto/grpc/testing/test.proto +++ b/src/proto/grpc/testing/test.proto @@ -70,8 +70,9 @@ service TestService { rpc HalfDuplexCall(stream StreamingOutputCallRequest) returns (stream StreamingOutputCallResponse); - // A call that no server should implement - rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty); + // The test server will not implement this method. It will be used + // to test the behavior when clients call unimplemented methods. + rpc UnimplementedMethod(grpc.testing.Empty) returns (grpc.testing.Empty); } // A simple service NOT implemented at servers so clients can test for diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc index b43f166b96c..65519a03a88 100644 --- a/test/cpp/interop/interop_client.cc +++ b/test/cpp/interop/interop_client.cc @@ -944,15 +944,15 @@ bool InteropClient::DoUnimplementedMethod() { Empty response = Empty::default_instance(); ClientContext context; - gpr_log(GPR_DEBUG, "here"); - - Status s = serviceStub_.Get()->UnimplementedCall( + Status s = serviceStub_.Get()->UnimplementedMethod( &context, request, &response); if (!AssertStatusCode(s, StatusCode::UNIMPLEMENTED)) { return false; } + GPR_ASSERT(s.error_message().empty()); + gpr_log(GPR_DEBUG, "unimplemented rpc done."); return true; } From 13a6008c55c1737262d55ee12c44393dcb419c08 Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Wed, 28 Sep 2016 15:28:22 -0700 Subject: [PATCH 03/14] updated interop test driver to run the advanced tests from a c++ client, since they are now all implemented --- tools/run_tests/run_interop_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 389d070d630..310cfe674ec 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -89,7 +89,7 @@ class CXXLanguage: return {} def unimplemented_test_cases(self): - return _SKIP_ADVANCED + return [] def unimplemented_test_cases_server(self): return _SKIP_ADVANCED From 2e9661c67176d0bf8eca8b1405ff78b9aa6efb42 Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Wed, 28 Sep 2016 16:41:36 -0700 Subject: [PATCH 04/14] Update interop-test-descriptions.md --- doc/interop-test-descriptions.md | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/doc/interop-test-descriptions.md b/doc/interop-test-descriptions.md index 1e04966380c..d9799c66c0e 100644 --- a/doc/interop-test-descriptions.md +++ b/doc/interop-test-descriptions.md @@ -750,9 +750,29 @@ Client asserts: ### unimplemented_method -Status: Ready for implementation. Blocking beta. +This test verifies that calling an unimplemented RPC method returns the +UNIMPLEMENTED status code -This test verifies calling unimplemented RPC method returns the UNIMPLEMENTED status code. +Server features: +N/A + +Procedure: +* Client calls `grpc.testing.TestService/UnimplementedMethod` with an empty + request (defined as `grpc.testing.Empty`): + + ``` + { + } + ``` + +Client asserts: +* received status code is 12 (UNIMPLEMENTED) +* received status message is empty or null/unset + +### unimplemented_service + +This test verifies calling an unimplemented server returns the UNIMPLEMENTED +status code. Server features: N/A From 55cb2363c64f7ee8e8d5822276e939eb60ac0ecc Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Wed, 28 Sep 2016 17:01:54 -0700 Subject: [PATCH 05/14] fixed typo in the updated interop test description file --- doc/interop-test-descriptions.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/doc/interop-test-descriptions.md b/doc/interop-test-descriptions.md index d9799c66c0e..6a3979d1176 100644 --- a/doc/interop-test-descriptions.md +++ b/doc/interop-test-descriptions.md @@ -751,7 +751,7 @@ Client asserts: ### unimplemented_method This test verifies that calling an unimplemented RPC method returns the -UNIMPLEMENTED status code +UNIMPLEMENTED status code. Server features: N/A @@ -779,12 +779,7 @@ N/A Procedure: * Client calls `grpc.testing.UnimplementedService/UnimplementedCall` with an - empty request (defined as `grpc.testing.Empty`): - - ``` - { - } - ``` + empty request (defined as `grpc.testing.Empty`) Client asserts: * received status code is 12 (UNIMPLEMENTED) From 0adb72808356704967d0478f56a862a3da2ee913 Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Thu, 29 Sep 2016 12:01:11 -0700 Subject: [PATCH 06/14] removed check for status error message. Investigating why node servers send messages back that are not empty --- test/cpp/interop/interop_client.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc index 65519a03a88..a54dd5a744e 100644 --- a/test/cpp/interop/interop_client.cc +++ b/test/cpp/interop/interop_client.cc @@ -135,7 +135,7 @@ bool InteropClient::AssertStatusOk(const Status& s) { } // Note: At this point, s.error_code is definitely not StatusCode::OK (we - // already checked for s.ok() above). So, the following will call abort() + // already checked for s.ok() all call abort() // (unless s.error_code() corresponds to a transient failure and // 'do_not_abort_on_transient_failures' is true) return AssertStatusCode(s, StatusCode::OK); @@ -951,8 +951,6 @@ bool InteropClient::DoUnimplementedMethod() { return false; } - GPR_ASSERT(s.error_message().empty()); - gpr_log(GPR_DEBUG, "unimplemented rpc done."); return true; } From 98b3663f6cdb119f1199b9cac8a88a3f84f52664 Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Thu, 29 Sep 2016 14:00:47 -0700 Subject: [PATCH 07/14] Fixed type in comments --- test/cpp/interop/interop_client.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc index a54dd5a744e..ea5a1fd8615 100644 --- a/test/cpp/interop/interop_client.cc +++ b/test/cpp/interop/interop_client.cc @@ -135,7 +135,7 @@ bool InteropClient::AssertStatusOk(const Status& s) { } // Note: At this point, s.error_code is definitely not StatusCode::OK (we - // already checked for s.ok() all call abort() + // already checked for s.ok() above). So, the following will call abort() // (unless s.error_code() corresponds to a transient failure and // 'do_not_abort_on_transient_failures' is true) return AssertStatusCode(s, StatusCode::OK); From 3b630f7f204fb49814406a6173cea23e37a7a299 Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Thu, 29 Sep 2016 18:00:39 -0700 Subject: [PATCH 08/14] updated interop test doc. unimplemented test no longer checks error message, since some server languages set it to empty string, and some set it to a non empty message --- doc/interop-test-descriptions.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/interop-test-descriptions.md b/doc/interop-test-descriptions.md index 6a3979d1176..2e1650eaf19 100644 --- a/doc/interop-test-descriptions.md +++ b/doc/interop-test-descriptions.md @@ -767,7 +767,6 @@ Procedure: Client asserts: * received status code is 12 (UNIMPLEMENTED) -* received status message is empty or null/unset ### unimplemented_service @@ -783,7 +782,6 @@ Procedure: Client asserts: * received status code is 12 (UNIMPLEMENTED) -* received status message is empty or null/unset ### cancel_after_begin From c5b927abce05bb389be81d8e38c71a9144743653 Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Fri, 30 Sep 2016 18:20:37 -0700 Subject: [PATCH 09/14] commit so docker picks up on out changes. will be rolled back --- tools/run_tests/run_interop_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 310cfe674ec..53c03f0bad4 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -92,7 +92,7 @@ class CXXLanguage: return [] def unimplemented_test_cases_server(self): - return _SKIP_ADVANCED + return [] def __str__(self): return 'c++' From 2cef11c6674e67aea8e7f63f7ac2869e5d44a7c5 Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Fri, 7 Oct 2016 15:35:48 -0700 Subject: [PATCH 10/14] added status request ability to the FullDuplexCall so that cpp server can pass the node client's status_code_and_message test --- test/cpp/interop/interop_server.cc | 38 ++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/test/cpp/interop/interop_server.cc b/test/cpp/interop/interop_server.cc index c05eb5d1461..0da37e15512 100644 --- a/test/cpp/interop/interop_server.cc +++ b/test/cpp/interop/interop_server.cc @@ -82,6 +82,8 @@ const char kEchoInitialMetadataKey[] = "x-grpc-test-echo-initial"; const char kEchoTrailingBinMetadataKey[] = "x-grpc-test-echo-trailing-bin"; const char kEchoUserAgentKey[] = "x-grpc-test-echo-useragent"; +namespace { + void MaybeEchoMetadata(ServerContext* context) { const auto& client_metadata = context->client_metadata(); GPR_ASSERT(client_metadata.count(kEchoInitialMetadataKey) <= 1); @@ -145,6 +147,28 @@ bool CheckExpectedCompression(const ServerContext& context, return true; } +Status RequestedStatusOrOk(const SimpleRequest* request) { + if (request->has_response_status()) { + return Status( + static_cast(request->response_status().code()), + request->response_status().message()); + } else { + return Status::OK; + } +} + +Status RequestedStatusOrOk(const StreamingOutputCallRequest* request) { + if (request->has_response_status()) { + return Status( + static_cast(request->response_status().code()), + request->response_status().message()); + } else { + return Status::OK; + } +} + +} // anonomous namespace + class TestServiceImpl : public TestService::Service { public: Status EmptyCall(ServerContext* context, const grpc::testing::Empty* request, @@ -179,13 +203,7 @@ class TestServiceImpl : public TestService::Service { } } - if (request->has_response_status()) { - return Status( - static_cast(request->response_status().code()), - request->response_status().message()); - } - - return Status::OK; + return RequestedStatusOrOk(request); } Status StreamingOutputCall( @@ -223,7 +241,7 @@ class TestServiceImpl : public TestService::Service { write_success = writer->Write(response, wopts); } if (write_success) { - return Status::OK; + return RequestedStatusOrOk(request); } else { return Status(grpc::StatusCode::INTERNAL, "Error writing response."); } @@ -273,7 +291,7 @@ class TestServiceImpl : public TestService::Service { } } if (write_success) { - return Status::OK; + return RequestedStatusOrOk(&request); } else { return Status(grpc::StatusCode::INTERNAL, "Error writing response."); } @@ -302,7 +320,7 @@ class TestServiceImpl : public TestService::Service { write_success = stream->Write(response); } if (write_success) { - return Status::OK; + return RequestedStatusOrOk(&request); } else { return Status(grpc::StatusCode::INTERNAL, "Error writing response."); } From 002f41ed28e687ef954b5837c66f27c32f34634e Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Wed, 12 Oct 2016 15:12:13 -0700 Subject: [PATCH 11/14] reverted changes to interop test driver to avoid clashes with mark roths pull req --- tools/run_tests/run_interop_tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py index 53c03f0bad4..389d070d630 100755 --- a/tools/run_tests/run_interop_tests.py +++ b/tools/run_tests/run_interop_tests.py @@ -89,10 +89,10 @@ class CXXLanguage: return {} def unimplemented_test_cases(self): - return [] + return _SKIP_ADVANCED def unimplemented_test_cases_server(self): - return [] + return _SKIP_ADVANCED def __str__(self): return 'c++' From f8ffbf62a2a44f152c2d88b388fe67de62cc1051 Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Wed, 12 Oct 2016 15:32:42 -0700 Subject: [PATCH 12/14] also reverted interop server, since mark had already made the changes I did in an un merged pull request --- test/cpp/interop/interop_server.cc | 50 ++++++------------------------ 1 file changed, 10 insertions(+), 40 deletions(-) diff --git a/test/cpp/interop/interop_server.cc b/test/cpp/interop/interop_server.cc index e0016148e80..c05eb5d1461 100644 --- a/test/cpp/interop/interop_server.cc +++ b/test/cpp/interop/interop_server.cc @@ -47,7 +47,6 @@ #include #include -#include "src/core/lib/support/string.h" #include "src/core/lib/transport/byte_stream.h" #include "src/proto/grpc/testing/empty.grpc.pb.h" #include "src/proto/grpc/testing/messages.grpc.pb.h" @@ -83,8 +82,6 @@ const char kEchoInitialMetadataKey[] = "x-grpc-test-echo-initial"; const char kEchoTrailingBinMetadataKey[] = "x-grpc-test-echo-trailing-bin"; const char kEchoUserAgentKey[] = "x-grpc-test-echo-useragent"; -namespace { - void MaybeEchoMetadata(ServerContext* context) { const auto& client_metadata = context->client_metadata(); GPR_ASSERT(client_metadata.count(kEchoInitialMetadataKey) <= 1); @@ -148,28 +145,6 @@ bool CheckExpectedCompression(const ServerContext& context, return true; } -Status RequestedStatusOrOk(const SimpleRequest* request) { - if (request->has_response_status()) { - return Status( - static_cast(request->response_status().code()), - request->response_status().message()); - } else { - return Status::OK; - } -} - -Status RequestedStatusOrOk(const StreamingOutputCallRequest* request) { - if (request->has_response_status()) { - return Status( - static_cast(request->response_status().code()), - request->response_status().message()); - } else { - return Status::OK; - } -} - -} // anonomous namespace - class TestServiceImpl : public TestService::Service { public: Status EmptyCall(ServerContext* context, const grpc::testing::Empty* request, @@ -178,17 +153,6 @@ class TestServiceImpl : public TestService::Service { return Status::OK; } - // Response contains current timestamp. We ignore everything in the request. - Status CacheableUnaryCall(ServerContext* context, - const SimpleRequest* request, - SimpleResponse* response) { - gpr_timespec ts = gpr_now(GPR_CLOCK_PRECISE); - std::string timestamp = std::to_string((long long unsigned)ts.tv_nsec); - response->mutable_payload()->set_body(timestamp.c_str(), timestamp.size()); - context->AddInitialMetadata("cache-control", "max-age=60, public"); - return Status::OK; - } - Status UnaryCall(ServerContext* context, const SimpleRequest* request, SimpleResponse* response) { MaybeEchoMetadata(context); @@ -215,7 +179,13 @@ class TestServiceImpl : public TestService::Service { } } - return RequestedStatusOrOk(request); + if (request->has_response_status()) { + return Status( + static_cast(request->response_status().code()), + request->response_status().message()); + } + + return Status::OK; } Status StreamingOutputCall( @@ -253,7 +223,7 @@ class TestServiceImpl : public TestService::Service { write_success = writer->Write(response, wopts); } if (write_success) { - return RequestedStatusOrOk(request); + return Status::OK; } else { return Status(grpc::StatusCode::INTERNAL, "Error writing response."); } @@ -303,7 +273,7 @@ class TestServiceImpl : public TestService::Service { } } if (write_success) { - return RequestedStatusOrOk(&request); + return Status::OK; } else { return Status(grpc::StatusCode::INTERNAL, "Error writing response."); } @@ -332,7 +302,7 @@ class TestServiceImpl : public TestService::Service { write_success = stream->Write(response); } if (write_success) { - return RequestedStatusOrOk(&request); + return Status::OK; } else { return Status(grpc::StatusCode::INTERNAL, "Error writing response."); } From 40860c4488363bd534b3440d4d09b1a946750667 Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Wed, 12 Oct 2016 15:38:46 -0700 Subject: [PATCH 13/14] reverting a file for the last commit caused a function to be deleted from interop_client. This commit adds that function back in --- test/cpp/interop/interop_server.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/cpp/interop/interop_server.cc b/test/cpp/interop/interop_server.cc index c05eb5d1461..2e6a10b36b8 100644 --- a/test/cpp/interop/interop_server.cc +++ b/test/cpp/interop/interop_server.cc @@ -47,6 +47,7 @@ #include #include +#include "src/core/lib/support/string.h" #include "src/core/lib/transport/byte_stream.h" #include "src/proto/grpc/testing/empty.grpc.pb.h" #include "src/proto/grpc/testing/messages.grpc.pb.h" @@ -153,6 +154,17 @@ class TestServiceImpl : public TestService::Service { return Status::OK; } + // Response contains current timestamp. We ignore everything in the request. + Status CacheableUnaryCall(ServerContext* context, + const SimpleRequest* request, + SimpleResponse* response) { + gpr_timespec ts = gpr_now(GPR_CLOCK_PRECISE); + std::string timestamp = std::to_string((long long unsigned)ts.tv_nsec); + response->mutable_payload()->set_body(timestamp.c_str(), timestamp.size()); + context->AddInitialMetadata("cache-control", "max-age=60, public"); + return Status::OK; + } + Status UnaryCall(ServerContext* context, const SimpleRequest* request, SimpleResponse* response) { MaybeEchoMetadata(context); From 83dd3aa7e056e2ea7e5b3b03f7e58e7a12bcc4e1 Mon Sep 17 00:00:00 2001 From: Noah Eisen Date: Wed, 12 Oct 2016 15:40:11 -0700 Subject: [PATCH 14/14] changed whitespace --- test/cpp/interop/interop_server.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/cpp/interop/interop_server.cc b/test/cpp/interop/interop_server.cc index 2e6a10b36b8..58f20aa611a 100644 --- a/test/cpp/interop/interop_server.cc +++ b/test/cpp/interop/interop_server.cc @@ -156,8 +156,8 @@ class TestServiceImpl : public TestService::Service { // Response contains current timestamp. We ignore everything in the request. Status CacheableUnaryCall(ServerContext* context, - const SimpleRequest* request, - SimpleResponse* response) { + const SimpleRequest* request, + SimpleResponse* response) { gpr_timespec ts = gpr_now(GPR_CLOCK_PRECISE); std::string timestamp = std::to_string((long long unsigned)ts.tv_nsec); response->mutable_payload()->set_body(timestamp.c_str(), timestamp.size());