grpc_cli json support

pull/16766/head
Feso 7 years ago
parent 95dc4f1b8d
commit 44cecbb2f7
  1. 7
      test/cpp/util/config_grpc_cli.h
  2. 85
      test/cpp/util/grpc_tool.cc
  3. 379
      test/cpp/util/grpc_tool_test.cc
  4. 81
      test/cpp/util/proto_file_parser.cc
  5. 20
      test/cpp/util/proto_file_parser.h

@ -40,6 +40,11 @@
#define GRPC_CUSTOM_TEXTFORMAT ::google::protobuf::TextFormat #define GRPC_CUSTOM_TEXTFORMAT ::google::protobuf::TextFormat
#endif #endif
#ifndef GRPC_CUSTOM_JSONUTIL
#include <google/protobuf/util/json_util.h>
#define GRPC_CUSTOM_JSONUTIL ::google::protobuf::util
#endif
#ifndef GRPC_CUSTOM_DISKSOURCETREE #ifndef GRPC_CUSTOM_DISKSOURCETREE
#include <google/protobuf/compiler/importer.h> #include <google/protobuf/compiler/importer.h>
#define GRPC_CUSTOM_DISKSOURCETREE ::google::protobuf::compiler::DiskSourceTree #define GRPC_CUSTOM_DISKSOURCETREE ::google::protobuf::compiler::DiskSourceTree
@ -58,6 +63,8 @@ typedef GRPC_CUSTOM_MERGEDDESCRIPTORDATABASE MergedDescriptorDatabase;
typedef GRPC_CUSTOM_TEXTFORMAT TextFormat; typedef GRPC_CUSTOM_TEXTFORMAT TextFormat;
namespace json = GRPC_CUSTOM_JSONUTIL;
namespace compiler { namespace compiler {
typedef GRPC_CUSTOM_DISKSOURCETREE DiskSourceTree; typedef GRPC_CUSTOM_DISKSOURCETREE DiskSourceTree;
typedef GRPC_CUSTOM_IMPORTER Importer; typedef GRPC_CUSTOM_IMPORTER Importer;

@ -57,6 +57,8 @@ DEFINE_string(proto_path, ".", "Path to look for the proto file.");
DEFINE_string(protofiles, "", "Name of the proto file."); DEFINE_string(protofiles, "", "Name of the proto file.");
DEFINE_bool(binary_input, false, "Input in binary format"); DEFINE_bool(binary_input, false, "Input in binary format");
DEFINE_bool(binary_output, false, "Output in binary format"); DEFINE_bool(binary_output, false, "Output in binary format");
DEFINE_bool(json_input, false, "Input in json format");
DEFINE_bool(json_output, false, "Output in json format");
DEFINE_string(infile, "", "Input file (default is stdin)"); DEFINE_string(infile, "", "Input file (default is stdin)");
DEFINE_bool(batch, false, DEFINE_bool(batch, false,
"Input contains multiple requests. Please do not use this to send " "Input contains multiple requests. Please do not use this to send "
@ -88,6 +90,8 @@ class GrpcTool {
GrpcToolOutputCallback callback); GrpcToolOutputCallback callback);
bool ToText(int argc, const char** argv, const CliCredentials& cred, bool ToText(int argc, const char** argv, const CliCredentials& cred,
GrpcToolOutputCallback callback); GrpcToolOutputCallback callback);
bool ToJson(int argc, const char** argv, const CliCredentials& cred,
GrpcToolOutputCallback callback);
bool ToBinary(int argc, const char** argv, const CliCredentials& cred, bool ToBinary(int argc, const char** argv, const CliCredentials& cred,
GrpcToolOutputCallback callback); GrpcToolOutputCallback callback);
@ -233,6 +237,7 @@ const Command ops[] = {
{"parse", BindWith5Args(&GrpcTool::ParseMessage), 2, 3}, {"parse", BindWith5Args(&GrpcTool::ParseMessage), 2, 3},
{"totext", BindWith5Args(&GrpcTool::ToText), 2, 3}, {"totext", BindWith5Args(&GrpcTool::ToText), 2, 3},
{"tobinary", BindWith5Args(&GrpcTool::ToBinary), 2, 3}, {"tobinary", BindWith5Args(&GrpcTool::ToBinary), 2, 3},
{"tojson", BindWith5Args(&GrpcTool::ToJson), 2, 3},
}; };
void Usage(const grpc::string& msg) { void Usage(const grpc::string& msg) {
@ -244,6 +249,7 @@ void Usage(const grpc::string& msg) {
" grpc_cli type ... ; Print type\n" " grpc_cli type ... ; Print type\n"
" grpc_cli parse ... ; Parse message\n" " grpc_cli parse ... ; Parse message\n"
" grpc_cli totext ... ; Convert binary message to text\n" " grpc_cli totext ... ; Convert binary message to text\n"
" grpc_cli tojson ... ; Convert binary message to json\n"
" grpc_cli tobinary ... ; Convert text message to binary\n" " grpc_cli tobinary ... ; Convert text message to binary\n"
" grpc_cli help ... ; Print this message, or per-command usage\n" " grpc_cli help ... ; Print this message, or per-command usage\n"
"\n", "\n",
@ -465,7 +471,9 @@ bool GrpcTool::CallMethod(int argc, const char** argv,
" --infile ; Input filename (defaults to stdin)\n" " --infile ; Input filename (defaults to stdin)\n"
" --outfile ; Output filename (defaults to stdout)\n" " --outfile ; Output filename (defaults to stdout)\n"
" --binary_input ; Input in binary format\n" " --binary_input ; Input in binary format\n"
" --binary_output ; Output in binary format\n" + " --binary_output ; Output in binary format\n"
" --json_input ; Input in json format\n"
" --json_output ; Output in json format\n" +
cred.GetCredentialUsage()); cred.GetCredentialUsage());
std::stringstream output_ss; std::stringstream output_ss;
@ -547,7 +555,11 @@ bool GrpcTool::CallMethod(int argc, const char** argv,
request_text.clear(); request_text.clear();
} else { } else {
gpr_mu_lock(&parser_mu); gpr_mu_lock(&parser_mu);
serialized_request_proto = parser->GetSerializedProtoFromMethod( serialized_request_proto =
FLAGS_json_input ?
parser->GetSerializedProtoFromMethodJsonFormat(
method_name, request_text, true /* is_request */) :
parser->GetSerializedProtoFromMethodTextFormat(
method_name, request_text, true /* is_request */); method_name, request_text, true /* is_request */);
request_text.clear(); request_text.clear();
if (parser->HasError()) { if (parser->HasError()) {
@ -631,7 +643,11 @@ bool GrpcTool::CallMethod(int argc, const char** argv,
serialized_request_proto = request_text; serialized_request_proto = request_text;
request_text.clear(); request_text.clear();
} else { } else {
serialized_request_proto = parser->GetSerializedProtoFromMethod( serialized_request_proto =
FLAGS_json_input ?
parser->GetSerializedProtoFromMethodJsonFormat(
method_name, request_text, true /* is_request */) :
parser->GetSerializedProtoFromMethodTextFormat(
method_name, request_text, true /* is_request */); method_name, request_text, true /* is_request */);
request_text.clear(); request_text.clear();
if (parser->HasError()) { if (parser->HasError()) {
@ -668,9 +684,15 @@ bool GrpcTool::CallMethod(int argc, const char** argv,
break; break;
} }
} else { } else {
grpc::string response_text = parser->GetTextFormatFromMethod( grpc::string response_text =
method_name, serialized_response_proto, FLAGS_json_output ?
parser->GetJsonFormatFromMethod(method_name,
serialized_response_proto,
false /* is_request */) :
parser->GetTextFormatFromMethod(method_name,
serialized_response_proto,
false /* is_request */); false /* is_request */);
if (parser->HasError() && print_mode) { if (parser->HasError() && print_mode) {
fprintf(stderr, "Failed to parse response.\n"); fprintf(stderr, "Failed to parse response.\n");
} else { } else {
@ -726,7 +748,11 @@ bool GrpcTool::CallMethod(int argc, const char** argv,
if (FLAGS_binary_input) { if (FLAGS_binary_input) {
serialized_request_proto = request_text; serialized_request_proto = request_text;
} else { } else {
serialized_request_proto = parser->GetSerializedProtoFromMethod( serialized_request_proto =
FLAGS_json_input ?
parser->GetSerializedProtoFromMethodJsonFormat(
method_name, request_text, true /* is_request */) :
parser->GetSerializedProtoFromMethodTextFormat(
method_name, request_text, true /* is_request */); method_name, request_text, true /* is_request */);
if (parser->HasError()) { if (parser->HasError()) {
fprintf(stderr, "Failed to parse request.\n"); fprintf(stderr, "Failed to parse request.\n");
@ -750,14 +776,20 @@ bool GrpcTool::CallMethod(int argc, const char** argv,
&serialized_response_proto, &serialized_response_proto,
receive_initial_metadata ? &server_initial_metadata : nullptr); receive_initial_metadata ? &server_initial_metadata : nullptr);
receive_initial_metadata = false) { receive_initial_metadata = false) {
if (!FLAGS_binary_output) { if (FLAGS_json_output) {
serialized_response_proto = parser->GetJsonFormatFromMethod(
method_name, serialized_response_proto, false /* is_request */);
} else if (!FLAGS_binary_output) {
serialized_response_proto = parser->GetTextFormatFromMethod( serialized_response_proto = parser->GetTextFormatFromMethod(
method_name, serialized_response_proto, false /* is_request */); method_name, serialized_response_proto, false /* is_request */);
}
if (FLAGS_json_output || !FLAGS_binary_output) {
if (parser->HasError()) { if (parser->HasError()) {
fprintf(stderr, "Failed to parse response.\n"); fprintf(stderr, "Failed to parse response.\n");
return false; return false;
} }
} }
if (receive_initial_metadata) { if (receive_initial_metadata) {
PrintMetadata(server_initial_metadata, PrintMetadata(server_initial_metadata,
"Received initial metadata from server:"); "Received initial metadata from server:");
@ -797,7 +829,9 @@ bool GrpcTool::ParseMessage(int argc, const char** argv,
" --infile ; Input filename (defaults to stdin)\n" " --infile ; Input filename (defaults to stdin)\n"
" --outfile ; Output filename (defaults to stdout)\n" " --outfile ; Output filename (defaults to stdout)\n"
" --binary_input ; Input in binary format\n" " --binary_input ; Input in binary format\n"
" --binary_output ; Output in binary format\n" + " --binary_output ; Output in binary format\n"
" --json_input ; Input in json format\n"
" --json_output ; Output in json format\n" +
cred.GetCredentialUsage()); cred.GetCredentialUsage());
std::stringstream output_ss; std::stringstream output_ss;
@ -845,7 +879,11 @@ bool GrpcTool::ParseMessage(int argc, const char** argv,
serialized_request_proto = message_text; serialized_request_proto = message_text;
} else { } else {
serialized_request_proto = serialized_request_proto =
parser->GetSerializedProtoFromMessageType(type_name, message_text); FLAGS_json_input ?
parser->GetSerializedProtoFromMessageTypeJsonFormat(type_name,
message_text) :
parser->GetSerializedProtoFromMessageTypeTextFormat(type_name,
message_text);
if (parser->HasError()) { if (parser->HasError()) {
fprintf(stderr, "Failed to serialize the message.\n"); fprintf(stderr, "Failed to serialize the message.\n");
return false; return false;
@ -855,12 +893,20 @@ bool GrpcTool::ParseMessage(int argc, const char** argv,
if (FLAGS_binary_output) { if (FLAGS_binary_output) {
output_ss << serialized_request_proto; output_ss << serialized_request_proto;
} else { } else {
grpc::string output_text = parser->GetTextFormatFromMessageType( grpc::string output_text;
if (FLAGS_json_output) {
output_text = parser->GetJsonFormatFromMessageType(
type_name, serialized_request_proto);
} else {
output_text = parser->GetTextFormatFromMessageType(
type_name, serialized_request_proto); type_name, serialized_request_proto);
}
if (parser->HasError()) { if (parser->HasError()) {
fprintf(stderr, "Failed to deserialize the message.\n"); fprintf(stderr, "Failed to deserialize the message.\n");
return false; return false;
} }
output_ss << output_text << std::endl; output_ss << output_text << std::endl;
} }
@ -885,6 +931,25 @@ bool GrpcTool::ToText(int argc, const char** argv, const CliCredentials& cred,
return ParseMessage(argc, argv, cred, callback); return ParseMessage(argc, argv, cred, callback);
} }
bool GrpcTool::ToJson(int argc, const char** argv, const CliCredentials& cred,
GrpcToolOutputCallback callback) {
CommandUsage(
"Convert binary message to json\n"
" grpc_cli tojson <protofiles> <type>\n"
" <protofiles> ; Comma separated list of proto files\n"
" <type> ; Protocol buffer type name\n"
" --proto_path ; The search path of proto files\n"
" --infile ; Input filename (defaults to stdin)\n"
" --outfile ; Output filename (defaults to stdout)\n");
FLAGS_protofiles = argv[0];
FLAGS_remotedb = false;
FLAGS_binary_input = true;
FLAGS_binary_output = false;
FLAGS_json_output = true;
return ParseMessage(argc, argv, cred, callback);
}
bool GrpcTool::ToBinary(int argc, const char** argv, const CliCredentials& cred, bool GrpcTool::ToBinary(int argc, const char** argv, const CliCredentials& cred,
GrpcToolOutputCallback callback) { GrpcToolOutputCallback callback) {
CommandUsage( CommandUsage(

@ -74,13 +74,22 @@ using grpc::testing::EchoResponse;
" rpc Echo(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) " \ " rpc Echo(grpc.testing.EchoRequest) returns (grpc.testing.EchoResponse) " \
"{}\n" "{}\n"
#define ECHO_RESPONSE_MESSAGE \ #define ECHO_RESPONSE_MESSAGE_TEXT_FORMAT \
"message: \"echo\"\n" \ "message: \"echo\"\n" \
"param {\n" \ "param {\n" \
" host: \"localhost\"\n" \ " host: \"localhost\"\n" \
" peer: \"peer\"\n" \ " peer: \"peer\"\n" \
"}\n\n" "}\n\n"
#define ECHO_RESPONSE_MESSAGE_JSON_FORMAT \
"{\n" \
" \"message\": \"echo\",\n" \
" \"param\": {\n" \
" \"host\": \"localhost\",\n" \
" \"peer\": \"peer\"\n" \
" }\n" \
"}\n\n"
DECLARE_string(channel_creds_type); DECLARE_string(channel_creds_type);
DECLARE_string(ssl_target); DECLARE_string(ssl_target);
@ -89,6 +98,8 @@ namespace testing {
DECLARE_bool(binary_input); DECLARE_bool(binary_input);
DECLARE_bool(binary_output); DECLARE_bool(binary_output);
DECLARE_bool(json_input);
DECLARE_bool(json_output);
DECLARE_bool(l); DECLARE_bool(l);
DECLARE_bool(batch); DECLARE_bool(batch);
DECLARE_string(metadata); DECLARE_string(metadata);
@ -426,6 +437,61 @@ TEST_F(GrpcToolTest, CallCommand) {
// Expected output: "message: \"Hello\"" // Expected output: "message: \"Hello\""
EXPECT_TRUE(nullptr != EXPECT_TRUE(nullptr !=
strstr(output_stream.str().c_str(), "message: \"Hello\"")); strstr(output_stream.str().c_str(), "message: \"Hello\""));
// with json_output
output_stream.str(grpc::string());
output_stream.clear();
FLAGS_json_output = true;
EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
std::bind(PrintStream, &output_stream,
std::placeholders::_1)));
FLAGS_json_output = false;
// Expected output:
// {
// "message": "Hello"
// }
EXPECT_TRUE(nullptr !=
strstr(output_stream.str().c_str(), "{\n \"message\": \"Hello\"\n}"));
ShutdownServer();
}
TEST_F(GrpcToolTest, CallCommandJsonInput) {
// Test input "grpc_cli call localhost:<port> Echo "{ \"message\": \"Hello\"}"
std::stringstream output_stream;
const grpc::string server_address = SetUpServer();
const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
"{ \"message\": \"Hello\"}"};
FLAGS_json_input = true;
EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
std::bind(PrintStream, &output_stream,
std::placeholders::_1)));
// Expected output: "message: \"Hello\""
EXPECT_TRUE(nullptr !=
strstr(output_stream.str().c_str(), "message: \"Hello\""));
// with json_output
output_stream.str(grpc::string());
output_stream.clear();
FLAGS_json_output = true;
EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
std::bind(PrintStream, &output_stream,
std::placeholders::_1)));
FLAGS_json_output = false;
FLAGS_json_input = false;
// Expected output:
// {
// "message": "Hello"
// }
EXPECT_TRUE(nullptr !=
strstr(output_stream.str().c_str(), "{\n \"message\": \"Hello\"\n}"));
ShutdownServer(); ShutdownServer();
} }
@ -453,6 +519,101 @@ TEST_F(GrpcToolTest, CallCommandBatch) {
EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(), EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
"message: \"Hello0\"\nmessage: " "message: \"Hello0\"\nmessage: "
"\"Hello1\"\nmessage: \"Hello2\"\n")); "\"Hello1\"\nmessage: \"Hello2\"\n"));
// with json_output
output_stream.str(grpc::string());
output_stream.clear();
ss.clear();
ss.seekg(0);
std::cin.rdbuf(ss.rdbuf());
FLAGS_batch = true;
FLAGS_json_output= true;
EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
std::bind(PrintStream, &output_stream,
std::placeholders::_1)));
FLAGS_json_output= false;
FLAGS_batch = false;
// Expected output:
// {
// "message": "Hello0"
// }
// {
// "message": "Hello1"
// }
// {
// "message": "Hello2"
// }
// Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
// "Hello2"\n"
EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
"{\n \"message\": \"Hello0\"\n}\n"
"{\n \"message\": \"Hello1\"\n}\n"
"{\n \"message\": \"Hello2\"\n}\n"));
std::cin.rdbuf(orig);
ShutdownServer();
}
TEST_F(GrpcToolTest, CallCommandBatchJsonInput) {
// Test input "grpc_cli call Echo"
std::stringstream output_stream;
const grpc::string server_address = SetUpServer();
const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
"{\"message\": \"Hello0\"}"};
// Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
std::streambuf* orig = std::cin.rdbuf();
std::istringstream ss("{\"message\": \"Hello1\"}\n\n{\"message\": \"Hello2\" }\n\n");
std::cin.rdbuf(ss.rdbuf());
FLAGS_json_input = true;
FLAGS_batch = true;
EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
std::bind(PrintStream, &output_stream,
std::placeholders::_1)));
FLAGS_batch = false;
// Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
// "Hello2"\n"
EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
"message: \"Hello0\"\nmessage: "
"\"Hello1\"\nmessage: \"Hello2\"\n"));
// with json_output
output_stream.str(grpc::string());
output_stream.clear();
ss.clear();
ss.seekg(0);
std::cin.rdbuf(ss.rdbuf());
FLAGS_batch = true;
FLAGS_json_output= true;
EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
std::bind(PrintStream, &output_stream,
std::placeholders::_1)));
FLAGS_json_output= false;
FLAGS_batch = false;
FLAGS_json_input = false;
// Expected output:
// {
// "message": "Hello0"
// }
// {
// "message": "Hello1"
// }
// {
// "message": "Hello2"
// }
// Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
// "Hello2"\n"
EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
"{\n \"message\": \"Hello0\"\n}\n"
"{\n \"message\": \"Hello1\"\n}\n"
"{\n \"message\": \"Hello2\"\n}\n"));
std::cin.rdbuf(orig); std::cin.rdbuf(orig);
ShutdownServer(); ShutdownServer();
} }
@ -479,6 +640,94 @@ TEST_F(GrpcToolTest, CallCommandBatchWithBadRequest) {
// Expected output: "message: "Hello0"\nmessage: "Hello2"\n" // Expected output: "message: "Hello0"\nmessage: "Hello2"\n"
EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(), EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
"message: \"Hello0\"\nmessage: \"Hello2\"\n")); "message: \"Hello0\"\nmessage: \"Hello2\"\n"));
// with json_output
output_stream.str(grpc::string());
output_stream.clear();
ss.clear();
ss.seekg(0);
std::cin.rdbuf(ss.rdbuf());
FLAGS_batch = true;
FLAGS_json_output= true;
EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
std::bind(PrintStream, &output_stream,
std::placeholders::_1)));
FLAGS_json_output= false;
FLAGS_batch = false;
// Expected output:
// {
// "message": "Hello0"
// }
// {
// "message": "Hello2"
// }
// Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
// "Hello2"\n"
EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
"{\n \"message\": \"Hello0\"\n}\n"
"{\n \"message\": \"Hello2\"\n}\n"));
std::cin.rdbuf(orig);
ShutdownServer();
}
TEST_F(GrpcToolTest, CallCommandBatchJsonInputWithBadRequest) {
// Test input "grpc_cli call Echo"
std::stringstream output_stream;
const grpc::string server_address = SetUpServer();
const char* argv[] = {"grpc_cli", "call", server_address.c_str(), "Echo",
"{ \"message\": \"Hello0\"}"};
// Mock std::cin input "message: 1\n\n message: 'Hello2'\n\n"
std::streambuf* orig = std::cin.rdbuf();
std::istringstream ss("{ \"message\": 1 }\n\n { \"message\": \"Hello2\" }\n\n");
std::cin.rdbuf(ss.rdbuf());
FLAGS_batch = true;
FLAGS_json_input = true;
EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
std::bind(PrintStream, &output_stream,
std::placeholders::_1)));
FLAGS_json_input = false;
FLAGS_batch = false;
// Expected output: "message: "Hello0"\nmessage: "Hello2"\n"
EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
"message: \"Hello0\"\nmessage: \"Hello2\"\n"));
// with json_output
output_stream.str(grpc::string());
output_stream.clear();
ss.clear();
ss.seekg(0);
std::cin.rdbuf(ss.rdbuf());
FLAGS_batch = true;
FLAGS_json_input = true;
FLAGS_json_output= true;
EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
std::bind(PrintStream, &output_stream,
std::placeholders::_1)));
FLAGS_json_output= false;
FLAGS_json_input = false;
FLAGS_batch = false;
// Expected output:
// {
// "message": "Hello0"
// }
// {
// "message": "Hello2"
// }
// Expected output: "message: "Hello0"\nmessage: "Hello1"\nmessage:
// "Hello2"\n"
EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
"{\n \"message\": \"Hello0\"\n}\n"
"{\n \"message\": \"Hello2\"\n}\n"));
std::cin.rdbuf(orig); std::cin.rdbuf(orig);
ShutdownServer(); ShutdownServer();
} }
@ -508,6 +757,33 @@ TEST_F(GrpcToolTest, CallCommandRequestStream) {
ShutdownServer(); ShutdownServer();
} }
TEST_F(GrpcToolTest, CallCommandRequestStreamJsonInput) {
// Test input: grpc_cli call localhost:<port> RequestStream "{ \"message\":
// \"Hello0\"}"
std::stringstream output_stream;
const grpc::string server_address = SetUpServer();
const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
"RequestStream", "{ \"message\": \"Hello0\" }"};
// Mock std::cin input "message: 'Hello1'\n\n message: 'Hello2'\n\n"
std::streambuf* orig = std::cin.rdbuf();
std::istringstream ss("{ \"message\": \"Hello1\" }\n\n{ \"message\": \"Hello2\" }\n\n");
std::cin.rdbuf(ss.rdbuf());
FLAGS_json_input = true;
EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
std::bind(PrintStream, &output_stream,
std::placeholders::_1)));
FLAGS_json_input = false;
// Expected output: "message: \"Hello0Hello1Hello2\""
EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
"message: \"Hello0Hello1Hello2\""));
std::cin.rdbuf(orig);
ShutdownServer();
}
TEST_F(GrpcToolTest, CallCommandRequestStreamWithBadRequest) { TEST_F(GrpcToolTest, CallCommandRequestStreamWithBadRequest) {
// Test input: grpc_cli call localhost:<port> RequestStream "message: // Test input: grpc_cli call localhost:<port> RequestStream "message:
// 'Hello0'" // 'Hello0'"
@ -533,6 +809,33 @@ TEST_F(GrpcToolTest, CallCommandRequestStreamWithBadRequest) {
ShutdownServer(); ShutdownServer();
} }
TEST_F(GrpcToolTest, CallCommandRequestStreamWithBadRequestJsonInput) {
// Test input: grpc_cli call localhost:<port> RequestStream "message:
// 'Hello0'"
std::stringstream output_stream;
const grpc::string server_address = SetUpServer();
const char* argv[] = {"grpc_cli", "call", server_address.c_str(),
"RequestStream", "{ \"message\": \"Hello0\" }"};
// Mock std::cin input "bad_field: 'Hello1'\n\n message: 'Hello2'\n\n"
std::streambuf* orig = std::cin.rdbuf();
std::istringstream ss("{ \"bad_field\": \"Hello1\" }\n\n{ \"message\": \"Hello2\" }\n\n");
std::cin.rdbuf(ss.rdbuf());
FLAGS_json_input = true;
EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
std::bind(PrintStream, &output_stream,
std::placeholders::_1)));
FLAGS_json_input = false;
// Expected output: "message: \"Hello0Hello2\""
EXPECT_TRUE(nullptr !=
strstr(output_stream.str().c_str(), "message: \"Hello0Hello2\""));
std::cin.rdbuf(orig);
ShutdownServer();
}
TEST_F(GrpcToolTest, CallCommandResponseStream) { TEST_F(GrpcToolTest, CallCommandResponseStream) {
// Test input: grpc_cli call localhost:<port> ResponseStream "message: // Test input: grpc_cli call localhost:<port> ResponseStream "message:
// 'Hello'" // 'Hello'"
@ -554,6 +857,24 @@ TEST_F(GrpcToolTest, CallCommandResponseStream) {
expected_response_text.c_str())); expected_response_text.c_str()));
} }
// with json_output
output_stream.str(grpc::string());
output_stream.clear();
FLAGS_json_output= true;
EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
std::bind(PrintStream, &output_stream,
std::placeholders::_1)));
FLAGS_json_output = false;
// Expected output: "{\n \"message\": \"Hello{n}\"\n}\n"
for (int i = 0; i < kServerDefaultResponseStreamsToSend; i++) {
grpc::string expected_response_text =
"{\n \"message\": \"Hello" + grpc::to_string(i) + "\"\n}\n";
EXPECT_TRUE(nullptr != strstr(output_stream.str().c_str(),
expected_response_text.c_str()));
}
ShutdownServer(); ShutdownServer();
} }
@ -617,15 +938,28 @@ TEST_F(GrpcToolTest, ParseCommand) {
const grpc::string server_address = SetUpServer(); const grpc::string server_address = SetUpServer();
const char* argv[] = {"grpc_cli", "parse", server_address.c_str(), const char* argv[] = {"grpc_cli", "parse", server_address.c_str(),
"grpc.testing.EchoResponse", ECHO_RESPONSE_MESSAGE}; "grpc.testing.EchoResponse", ECHO_RESPONSE_MESSAGE_TEXT_FORMAT};
FLAGS_binary_input = false; FLAGS_binary_input = false;
FLAGS_binary_output = false; FLAGS_binary_output = false;
EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(), EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
std::bind(PrintStream, &output_stream, std::bind(PrintStream, &output_stream,
std::placeholders::_1))); std::placeholders::_1)));
// Expected output: ECHO_RESPONSE_MESSAGE // Expected output: ECHO_RESPONSE_MESSAGE_TEXT_FORMAT
EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), ECHO_RESPONSE_MESSAGE)); EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), ECHO_RESPONSE_MESSAGE_TEXT_FORMAT));
// with json_output
output_stream.str(grpc::string());
output_stream.clear();
FLAGS_json_output = true;
EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
std::bind(PrintStream, &output_stream,
std::placeholders::_1)));
FLAGS_json_output = false;
// Expected output: ECHO_RESPONSE_MESSAGE_JSON_FORMAT
EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), ECHO_RESPONSE_MESSAGE_JSON_FORMAT));
// Parse text message to binary message and then parse it back to text message // Parse text message to binary message and then parse it back to text message
output_stream.str(grpc::string()); output_stream.str(grpc::string());
@ -645,13 +979,48 @@ TEST_F(GrpcToolTest, ParseCommand) {
std::placeholders::_1))); std::placeholders::_1)));
// Expected output: ECHO_RESPONSE_MESSAGE // Expected output: ECHO_RESPONSE_MESSAGE
EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), ECHO_RESPONSE_MESSAGE)); EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), ECHO_RESPONSE_MESSAGE_TEXT_FORMAT));
FLAGS_binary_input = false; FLAGS_binary_input = false;
FLAGS_binary_output = false; FLAGS_binary_output = false;
ShutdownServer(); ShutdownServer();
} }
TEST_F(GrpcToolTest, ParseCommandJsonFormat) {
// Test input "grpc_cli parse localhost:<port> grpc.testing.EchoResponse
// ECHO_RESPONSE_MESSAGE_JSON_FORMAT"
std::stringstream output_stream;
std::stringstream binary_output_stream;
const grpc::string server_address = SetUpServer();
const char* argv[] = {"grpc_cli", "parse", server_address.c_str(),
"grpc.testing.EchoResponse", ECHO_RESPONSE_MESSAGE_JSON_FORMAT};
FLAGS_json_input = true;
EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
std::bind(PrintStream, &output_stream,
std::placeholders::_1)));
// Expected output: ECHO_RESPONSE_MESSAGE_TEXT_FORMAT
EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), ECHO_RESPONSE_MESSAGE_TEXT_FORMAT));
// with json_output
output_stream.str(grpc::string());
output_stream.clear();
FLAGS_json_output = true;
EXPECT_TRUE(0 == GrpcToolMainLib(ArraySize(argv), argv, TestCliCredentials(),
std::bind(PrintStream, &output_stream,
std::placeholders::_1)));
FLAGS_json_output = false;
FLAGS_json_input = false;
// Expected output: ECHO_RESPONSE_MESSAGE_JSON_FORMAT
EXPECT_TRUE(0 == strcmp(output_stream.str().c_str(), ECHO_RESPONSE_MESSAGE_JSON_FORMAT));
ShutdownServer();
}
TEST_F(GrpcToolTest, TooFewArguments) { TEST_F(GrpcToolTest, TooFewArguments) {
// Test input "grpc_cli call Echo" // Test input "grpc_cli call Echo"
std::stringstream output_stream; std::stringstream output_stream;

@ -216,7 +216,7 @@ bool ProtoFileParser::IsStreaming(const grpc::string& method, bool is_request) {
: method_desc->server_streaming(); : method_desc->server_streaming();
} }
grpc::string ProtoFileParser::GetSerializedProtoFromMethod( grpc::string ProtoFileParser::GetSerializedProtoFromMethodTextFormat(
const grpc::string& method, const grpc::string& text_format_proto, const grpc::string& method, const grpc::string& text_format_proto,
bool is_request) { bool is_request) {
has_error_ = false; has_error_ = false;
@ -224,10 +224,22 @@ grpc::string ProtoFileParser::GetSerializedProtoFromMethod(
if (has_error_) { if (has_error_) {
return ""; return "";
} }
return GetSerializedProtoFromMessageType(message_type_name, return GetSerializedProtoFromMessageTypeTextFormat(message_type_name,
text_format_proto); text_format_proto);
} }
grpc::string ProtoFileParser::GetSerializedProtoFromMethodJsonFormat(
const grpc::string& method, const grpc::string& json_format_proto,
bool is_request) {
has_error_ = false;
grpc::string message_type_name = GetMessageTypeFromMethod(method, is_request);
if (has_error_) {
return "";
}
return GetSerializedProtoFromMessageTypeJsonFormat(message_type_name,
json_format_proto);
}
grpc::string ProtoFileParser::GetTextFormatFromMethod( grpc::string ProtoFileParser::GetTextFormatFromMethod(
const grpc::string& method, const grpc::string& serialized_proto, const grpc::string& method, const grpc::string& serialized_proto,
bool is_request) { bool is_request) {
@ -239,7 +251,18 @@ grpc::string ProtoFileParser::GetTextFormatFromMethod(
return GetTextFormatFromMessageType(message_type_name, serialized_proto); return GetTextFormatFromMessageType(message_type_name, serialized_proto);
} }
grpc::string ProtoFileParser::GetSerializedProtoFromMessageType( grpc::string ProtoFileParser::GetJsonFormatFromMethod(
const grpc::string& method, const grpc::string& serialized_proto,
bool is_request) {
has_error_ = false;
grpc::string message_type_name = GetMessageTypeFromMethod(method, is_request);
if (has_error_) {
return "";
}
return GetJsonFormatFromMessageType(message_type_name, serialized_proto);
}
grpc::string ProtoFileParser::GetSerializedProtoFromMessageTypeTextFormat(
const grpc::string& message_type_name, const grpc::string& message_type_name,
const grpc::string& text_format_proto) { const grpc::string& text_format_proto) {
has_error_ = false; has_error_ = false;
@ -265,6 +288,32 @@ grpc::string ProtoFileParser::GetSerializedProtoFromMessageType(
return serialized; return serialized;
} }
grpc::string ProtoFileParser::GetSerializedProtoFromMessageTypeJsonFormat(
const grpc::string& message_type_name,
const grpc::string& json_format_proto) {
has_error_ = false;
grpc::string serialized;
const protobuf::Descriptor* desc =
desc_pool_->FindMessageTypeByName(message_type_name);
if (!desc) {
LogError("Message type not found");
return "";
}
std::unique_ptr<grpc::protobuf::Message> msg(
dynamic_factory_->GetPrototype(desc)->New());
if (!grpc::protobuf::json::JsonStringToMessage(json_format_proto, msg.get()).ok()) {
LogError("Failed to parse json format to proto.");
return "";
}
bool ok = msg->SerializeToString(&serialized);
if (!ok) {
LogError("Failed to serialize proto.");
return "";
}
return serialized;
}
grpc::string ProtoFileParser::GetTextFormatFromMessageType( grpc::string ProtoFileParser::GetTextFormatFromMessageType(
const grpc::string& message_type_name, const grpc::string& message_type_name,
const grpc::string& serialized_proto) { const grpc::string& serialized_proto) {
@ -289,6 +338,32 @@ grpc::string ProtoFileParser::GetTextFormatFromMessageType(
return text_format; return text_format;
} }
grpc::string ProtoFileParser::GetJsonFormatFromMessageType(
const grpc::string& message_type_name,
const grpc::string& serialized_proto) {
has_error_ = false;
const protobuf::Descriptor* desc =
desc_pool_->FindMessageTypeByName(message_type_name);
if (!desc) {
LogError("Message type not found");
return "";
}
std::unique_ptr<grpc::protobuf::Message> msg(
dynamic_factory_->GetPrototype(desc)->New());
if (!msg->ParseFromString(serialized_proto)) {
LogError("Failed to deserialize proto.");
return "";
}
grpc::string json_format;
grpc::protobuf::json::JsonPrintOptions jsonPrintOptions;
jsonPrintOptions.add_whitespace = true;
if (!grpc::protobuf::json::MessageToJsonString(*msg.get(), &json_format, jsonPrintOptions).ok()) {
LogError("Failed to print proto message to json format");
return "";
}
return json_format;
}
void ProtoFileParser::LogError(const grpc::string& error_msg) { void ProtoFileParser::LogError(const grpc::string& error_msg) {
if (!error_msg.empty()) { if (!error_msg.empty()) {
std::cerr << error_msg << std::endl; std::cerr << error_msg << std::endl;

@ -53,22 +53,38 @@ class ProtoFileParser {
// used as the argument of Stub::Call() // used as the argument of Stub::Call()
grpc::string GetFormattedMethodName(const grpc::string& method); grpc::string GetFormattedMethodName(const grpc::string& method);
grpc::string GetSerializedProtoFromMethod( grpc::string GetSerializedProtoFromMethodTextFormat(
const grpc::string& method, const grpc::string& text_format_proto, const grpc::string& method, const grpc::string& text_format_proto,
bool is_request); bool is_request);
grpc::string GetSerializedProtoFromMethodJsonFormat(
const grpc::string& method, const grpc::string& json_format_proto,
bool is_request);
grpc::string GetTextFormatFromMethod(const grpc::string& method, grpc::string GetTextFormatFromMethod(const grpc::string& method,
const grpc::string& serialized_proto, const grpc::string& serialized_proto,
bool is_request); bool is_request);
grpc::string GetSerializedProtoFromMessageType( grpc::string GetJsonFormatFromMethod(const grpc::string& method,
const grpc::string& serialized_proto,
bool is_request);
grpc::string GetSerializedProtoFromMessageTypeTextFormat(
const grpc::string& message_type_name, const grpc::string& message_type_name,
const grpc::string& text_format_proto); const grpc::string& text_format_proto);
grpc::string GetSerializedProtoFromMessageTypeJsonFormat(
const grpc::string& message_type_name,
const grpc::string& json_format_proto);
grpc::string GetTextFormatFromMessageType( grpc::string GetTextFormatFromMessageType(
const grpc::string& message_type_name, const grpc::string& message_type_name,
const grpc::string& serialized_proto); const grpc::string& serialized_proto);
grpc::string GetJsonFormatFromMessageType(
const grpc::string& message_type_name,
const grpc::string& serialized_proto);
bool IsStreaming(const grpc::string& method, bool is_request); bool IsStreaming(const grpc::string& method, bool is_request);
bool HasError() const { return has_error_; } bool HasError() const { return has_error_; }

Loading…
Cancel
Save