|  | @@ -16,6 +16,10 @@
 | 
	
		
			
				|  |  |   *
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#include <condition_variable>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#include <grpcpp/channel.h>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  #include "src/proto/grpc/testing/echo.grpc.pb.h"
 | 
	
		
			
				|  |  |  #include "test/cpp/util/string_ref_helper.h"
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -23,6 +27,54 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  namespace grpc {
 | 
	
		
			
				|  |  |  namespace testing {
 | 
	
		
			
				|  |  | +/* This interceptor does nothing. Just keeps a global count on the number of
 | 
	
		
			
				|  |  | + * times it was invoked. */
 | 
	
		
			
				|  |  | +class DummyInterceptor : public experimental::Interceptor {
 | 
	
		
			
				|  |  | + public:
 | 
	
		
			
				|  |  | +  DummyInterceptor() {}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  virtual void Intercept(experimental::InterceptorBatchMethods* methods) {
 | 
	
		
			
				|  |  | +    if (methods->QueryInterceptionHookPoint(
 | 
	
		
			
				|  |  | +            experimental::InterceptionHookPoints::PRE_SEND_INITIAL_METADATA)) {
 | 
	
		
			
				|  |  | +      num_times_run_++;
 | 
	
		
			
				|  |  | +    } else if (methods->QueryInterceptionHookPoint(
 | 
	
		
			
				|  |  | +                   experimental::InterceptionHookPoints::
 | 
	
		
			
				|  |  | +                       POST_RECV_INITIAL_METADATA)) {
 | 
	
		
			
				|  |  | +      num_times_run_reverse_++;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    methods->Proceed();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  static void Reset() {
 | 
	
		
			
				|  |  | +    num_times_run_.store(0);
 | 
	
		
			
				|  |  | +    num_times_run_reverse_.store(0);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  static int GetNumTimesRun() {
 | 
	
		
			
				|  |  | +    EXPECT_EQ(num_times_run_.load(), num_times_run_reverse_.load());
 | 
	
		
			
				|  |  | +    return num_times_run_.load();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | + private:
 | 
	
		
			
				|  |  | +  static std::atomic<int> num_times_run_;
 | 
	
		
			
				|  |  | +  static std::atomic<int> num_times_run_reverse_;
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class DummyInterceptorFactory
 | 
	
		
			
				|  |  | +    : public experimental::ClientInterceptorFactoryInterface,
 | 
	
		
			
				|  |  | +      public experimental::ServerInterceptorFactoryInterface {
 | 
	
		
			
				|  |  | + public:
 | 
	
		
			
				|  |  | +  virtual experimental::Interceptor* CreateClientInterceptor(
 | 
	
		
			
				|  |  | +      experimental::ClientRpcInfo* info) override {
 | 
	
		
			
				|  |  | +    return new DummyInterceptor();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  virtual experimental::Interceptor* CreateServerInterceptor(
 | 
	
		
			
				|  |  | +      experimental::ServerRpcInfo* info) override {
 | 
	
		
			
				|  |  | +    return new DummyInterceptor();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  class EchoTestServiceStreamingImpl : public EchoTestService::Service {
 | 
	
		
			
				|  |  |   public:
 | 
	
		
			
				|  |  |    ~EchoTestServiceStreamingImpl() override {}
 | 
	
	
		
			
				|  | @@ -77,115 +129,23 @@ class EchoTestServiceStreamingImpl : public EchoTestService::Service {
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void MakeCall(const std::shared_ptr<Channel>& channel) {
 | 
	
		
			
				|  |  | -  auto stub = grpc::testing::EchoTestService::NewStub(channel);
 | 
	
		
			
				|  |  | -  ClientContext ctx;
 | 
	
		
			
				|  |  | -  EchoRequest req;
 | 
	
		
			
				|  |  | -  req.mutable_param()->set_echo_metadata(true);
 | 
	
		
			
				|  |  | -  ctx.AddMetadata("testkey", "testvalue");
 | 
	
		
			
				|  |  | -  req.set_message("Hello");
 | 
	
		
			
				|  |  | -  EchoResponse resp;
 | 
	
		
			
				|  |  | -  Status s = stub->Echo(&ctx, req, &resp);
 | 
	
		
			
				|  |  | -  EXPECT_EQ(s.ok(), true);
 | 
	
		
			
				|  |  | -  EXPECT_EQ(resp.message(), "Hello");
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | +void MakeCall(const std::shared_ptr<Channel>& channel);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void MakeClientStreamingCall(const std::shared_ptr<Channel>& channel) {
 | 
	
		
			
				|  |  | -  auto stub = grpc::testing::EchoTestService::NewStub(channel);
 | 
	
		
			
				|  |  | -  ClientContext ctx;
 | 
	
		
			
				|  |  | -  EchoRequest req;
 | 
	
		
			
				|  |  | -  req.mutable_param()->set_echo_metadata(true);
 | 
	
		
			
				|  |  | -  ctx.AddMetadata("testkey", "testvalue");
 | 
	
		
			
				|  |  | -  req.set_message("Hello");
 | 
	
		
			
				|  |  | -  EchoResponse resp;
 | 
	
		
			
				|  |  | -  string expected_resp = "";
 | 
	
		
			
				|  |  | -  auto writer = stub->RequestStream(&ctx, &resp);
 | 
	
		
			
				|  |  | -  for (int i = 0; i < 10; i++) {
 | 
	
		
			
				|  |  | -    writer->Write(req);
 | 
	
		
			
				|  |  | -    expected_resp += "Hello";
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  writer->WritesDone();
 | 
	
		
			
				|  |  | -  Status s = writer->Finish();
 | 
	
		
			
				|  |  | -  EXPECT_EQ(s.ok(), true);
 | 
	
		
			
				|  |  | -  EXPECT_EQ(resp.message(), expected_resp);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | +void MakeClientStreamingCall(const std::shared_ptr<Channel>& channel);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void MakeServerStreamingCall(const std::shared_ptr<Channel>& channel) {
 | 
	
		
			
				|  |  | -  auto stub = grpc::testing::EchoTestService::NewStub(channel);
 | 
	
		
			
				|  |  | -  ClientContext ctx;
 | 
	
		
			
				|  |  | -  EchoRequest req;
 | 
	
		
			
				|  |  | -  req.mutable_param()->set_echo_metadata(true);
 | 
	
		
			
				|  |  | -  ctx.AddMetadata("testkey", "testvalue");
 | 
	
		
			
				|  |  | -  req.set_message("Hello");
 | 
	
		
			
				|  |  | -  EchoResponse resp;
 | 
	
		
			
				|  |  | -  string expected_resp = "";
 | 
	
		
			
				|  |  | -  auto reader = stub->ResponseStream(&ctx, req);
 | 
	
		
			
				|  |  | -  int count = 0;
 | 
	
		
			
				|  |  | -  while (reader->Read(&resp)) {
 | 
	
		
			
				|  |  | -    EXPECT_EQ(resp.message(), "Hello");
 | 
	
		
			
				|  |  | -    count++;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  ASSERT_EQ(count, 10);
 | 
	
		
			
				|  |  | -  Status s = reader->Finish();
 | 
	
		
			
				|  |  | -  EXPECT_EQ(s.ok(), true);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | +void MakeServerStreamingCall(const std::shared_ptr<Channel>& channel);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void MakeBidiStreamingCall(const std::shared_ptr<Channel>& channel) {
 | 
	
		
			
				|  |  | -  auto stub = grpc::testing::EchoTestService::NewStub(channel);
 | 
	
		
			
				|  |  | -  ClientContext ctx;
 | 
	
		
			
				|  |  | -  EchoRequest req;
 | 
	
		
			
				|  |  | -  EchoResponse resp;
 | 
	
		
			
				|  |  | -  ctx.AddMetadata("testkey", "testvalue");
 | 
	
		
			
				|  |  | -  auto stream = stub->BidiStream(&ctx);
 | 
	
		
			
				|  |  | -  for (auto i = 0; i < 10; i++) {
 | 
	
		
			
				|  |  | -    req.set_message("Hello" + std::to_string(i));
 | 
	
		
			
				|  |  | -    stream->Write(req);
 | 
	
		
			
				|  |  | -    stream->Read(&resp);
 | 
	
		
			
				|  |  | -    EXPECT_EQ(req.message(), resp.message());
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  ASSERT_TRUE(stream->WritesDone());
 | 
	
		
			
				|  |  | -  Status s = stream->Finish();
 | 
	
		
			
				|  |  | -  EXPECT_EQ(s.ok(), true);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | +void MakeBidiStreamingCall(const std::shared_ptr<Channel>& channel);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void MakeCallbackCall(const std::shared_ptr<Channel>& channel) {
 | 
	
		
			
				|  |  | -  auto stub = grpc::testing::EchoTestService::NewStub(channel);
 | 
	
		
			
				|  |  | -  ClientContext ctx;
 | 
	
		
			
				|  |  | -  EchoRequest req;
 | 
	
		
			
				|  |  | -  std::mutex mu;
 | 
	
		
			
				|  |  | -  std::condition_variable cv;
 | 
	
		
			
				|  |  | -  bool done = false;
 | 
	
		
			
				|  |  | -  req.mutable_param()->set_echo_metadata(true);
 | 
	
		
			
				|  |  | -  ctx.AddMetadata("testkey", "testvalue");
 | 
	
		
			
				|  |  | -  req.set_message("Hello");
 | 
	
		
			
				|  |  | -  EchoResponse resp;
 | 
	
		
			
				|  |  | -  stub->experimental_async()->Echo(&ctx, &req, &resp,
 | 
	
		
			
				|  |  | -                                   [&resp, &mu, &done, &cv](Status s) {
 | 
	
		
			
				|  |  | -                                     // gpr_log(GPR_ERROR, "got the callback");
 | 
	
		
			
				|  |  | -                                     EXPECT_EQ(s.ok(), true);
 | 
	
		
			
				|  |  | -                                     EXPECT_EQ(resp.message(), "Hello");
 | 
	
		
			
				|  |  | -                                     std::lock_guard<std::mutex> l(mu);
 | 
	
		
			
				|  |  | -                                     done = true;
 | 
	
		
			
				|  |  | -                                     cv.notify_one();
 | 
	
		
			
				|  |  | -                                   });
 | 
	
		
			
				|  |  | -  std::unique_lock<std::mutex> l(mu);
 | 
	
		
			
				|  |  | -  while (!done) {
 | 
	
		
			
				|  |  | -    cv.wait(l);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | +void MakeCallbackCall(const std::shared_ptr<Channel>& channel);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  bool CheckMetadata(const std::multimap<grpc::string_ref, grpc::string_ref>& map,
 | 
	
		
			
				|  |  | -                   const string& key, const string& value) {
 | 
	
		
			
				|  |  | -  for (const auto& pair : map) {
 | 
	
		
			
				|  |  | -    if (pair.first.starts_with(key) && pair.second.starts_with(value)) {
 | 
	
		
			
				|  |  | -      return true;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  return false;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | +                   const string& key, const string& value);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void* tag(int i) { return (void*)static_cast<intptr_t>(i); }
 | 
	
		
			
				|  |  | -int detag(void* p) { return static_cast<int>(reinterpret_cast<intptr_t>(p)); }
 | 
	
		
			
				|  |  | +inline void* tag(int i) { return (void*)static_cast<intptr_t>(i); }
 | 
	
		
			
				|  |  | +inline int detag(void* p) {
 | 
	
		
			
				|  |  | +  return static_cast<int>(reinterpret_cast<intptr_t>(p));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  class Verifier {
 | 
	
		
			
				|  |  |   public:
 |