I'm attempting to create some test drivers for some C++ applications that communicate over gRPC. Most of these test drivers simply use grpcurl to fire off some messages to the applications under tests and verify the responses.
Some of our apps, however, connect to streaming RPCs. It would be trivial to write a test driver app that serves all the streams we need; however I was hoping to make something a bit more generic. My idea was to write an app that could take in a descriptor set, the name of the streaming method to serve, and a JSON file defining the message to serve out when applications connect to the streaming RPC.
Parsing the descriptor set (generated via protoc's --descriptor_set_out
argument), getting service and method descriptors for the streaming method, and loading the message to return from a JSON file were all pretty easy. Where I'm hung up is actually creating the service from the descriptor.
Here's the code I threw together as a quick proof-of-concept - note no error checking / hardcoded paths, I'm just trying to quickly see if this will work:
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/dynamic_message.h"
#include "google/protobuf/util/json_util.h"
#include <fstream>
#include <sstream>
int main(int argc, char** argv)
{
google::protobuf::FileDescriptorSet desc;
std::stringstream sst;
{
std::ifstream i("/tmp/test.protoset");
sst << i.rdbuf();
}
desc.ParseFromString(sst.str());
google::protobuf::DescriptorPool desc_pool;
for (const auto& fdesc : desc.file())
{
desc_pool.BuildFile(fdesc);
}
auto sdesc = desc_pool.FindServiceByName("TestService");
auto mdesc = sdesc->FindMethodByName("connect");
auto resp_type = mdesc->output_type();
google::protobuf::DynamicMessageFactory dmf(&desc_pool);
sst.str("");
sst.clear();
auto out_message = std::shared_ptr<google::protobuf::Message>(dmf.GetPrototype(resp_type)->New());
{
std::ifstream i("/tmp/test_message.json");
sst << i.rdbuf();
}
auto stat = google::protobuf::util::JsonStringToMessage(sst.str(), out_message.get());
std::cout << "READ " << stat << " " << out_message->DebugString() << std::endl;
}
Is it now in any way possible to actually create the "TestService/connect" streaming rpc, wait for a connection, and return the message built in out_message
?
There are a couple of ways to achieve this and one of which would be using gRPC C++ GenericService. By doing so, you can handle all methods without pre-declaring them.