|  | @@ -32,6 +32,7 @@
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #include <memory>
 | 
	
		
			
				|  |  | +#include <thread>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #include <grpc++/channel.h>
 | 
	
		
			
				|  |  |  #include <grpc++/client_context.h>
 | 
	
	
		
			
				|  | @@ -104,7 +105,10 @@ class Verifier : public PollingCheckRegion {
 | 
	
		
			
				|  |  |      expectations_[tag(i)] = expect_ok;
 | 
	
		
			
				|  |  |      return *this;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  void Verify(CompletionQueue* cq) {
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  void Verify(CompletionQueue* cq) { Verify(cq, false); }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  void Verify(CompletionQueue* cq, bool ignore_ok) {
 | 
	
		
			
				|  |  |      GPR_ASSERT(!expectations_.empty());
 | 
	
		
			
				|  |  |      while (!expectations_.empty()) {
 | 
	
		
			
				|  |  |        bool ok;
 | 
	
	
		
			
				|  | @@ -122,7 +126,9 @@ class Verifier : public PollingCheckRegion {
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        auto it = expectations_.find(got_tag);
 | 
	
		
			
				|  |  |        EXPECT_TRUE(it != expectations_.end());
 | 
	
		
			
				|  |  | -      EXPECT_EQ(it->second, ok);
 | 
	
		
			
				|  |  | +      if (!ignore_ok) {
 | 
	
		
			
				|  |  | +        EXPECT_EQ(it->second, ok);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |        expectations_.erase(it);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -217,7 +223,7 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<bool> {
 | 
	
		
			
				|  |  |        grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        send_request.set_message("Hello");
 | 
	
		
			
				|  |  | -      std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
 | 
	
		
			
				|  |  | +      std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
 | 
	
		
			
				|  |  |            stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
 | 
	
	
		
			
				|  | @@ -270,7 +276,7 @@ TEST_P(AsyncEnd2endTest, AsyncNextRpc) {
 | 
	
		
			
				|  |  |    grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    send_request.set_message("Hello");
 | 
	
		
			
				|  |  | -  std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
 | 
	
		
			
				|  |  | +  std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
 | 
	
		
			
				|  |  |        stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    std::chrono::system_clock::time_point time_now(
 | 
	
	
		
			
				|  | @@ -315,7 +321,7 @@ TEST_P(AsyncEnd2endTest, SimpleClientStreaming) {
 | 
	
		
			
				|  |  |    ServerAsyncReader<EchoResponse, EchoRequest> srv_stream(&srv_ctx);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    send_request.set_message("Hello");
 | 
	
		
			
				|  |  | -  std::unique_ptr<ClientAsyncWriter<EchoRequest> > cli_stream(
 | 
	
		
			
				|  |  | +  std::unique_ptr<ClientAsyncWriter<EchoRequest>> cli_stream(
 | 
	
		
			
				|  |  |        stub_->AsyncRequestStream(&cli_ctx, &recv_response, cq_.get(), tag(1)));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    service_.RequestRequestStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(),
 | 
	
	
		
			
				|  | @@ -368,7 +374,7 @@ TEST_P(AsyncEnd2endTest, SimpleServerStreaming) {
 | 
	
		
			
				|  |  |    ServerAsyncWriter<EchoResponse> srv_stream(&srv_ctx);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    send_request.set_message("Hello");
 | 
	
		
			
				|  |  | -  std::unique_ptr<ClientAsyncReader<EchoResponse> > cli_stream(
 | 
	
		
			
				|  |  | +  std::unique_ptr<ClientAsyncReader<EchoResponse>> cli_stream(
 | 
	
		
			
				|  |  |        stub_->AsyncResponseStream(&cli_ctx, send_request, cq_.get(), tag(1)));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    service_.RequestResponseStream(&srv_ctx, &recv_request, &srv_stream,
 | 
	
	
		
			
				|  | @@ -418,7 +424,7 @@ TEST_P(AsyncEnd2endTest, SimpleBidiStreaming) {
 | 
	
		
			
				|  |  |    ServerAsyncReaderWriter<EchoResponse, EchoRequest> srv_stream(&srv_ctx);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    send_request.set_message("Hello");
 | 
	
		
			
				|  |  | -  std::unique_ptr<ClientAsyncReaderWriter<EchoRequest, EchoResponse> >
 | 
	
		
			
				|  |  | +  std::unique_ptr<ClientAsyncReaderWriter<EchoRequest, EchoResponse>>
 | 
	
		
			
				|  |  |        cli_stream(stub_->AsyncBidiStream(&cli_ctx, cq_.get(), tag(1)));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    service_.RequestBidiStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(),
 | 
	
	
		
			
				|  | @@ -476,7 +482,7 @@ TEST_P(AsyncEnd2endTest, ClientInitialMetadataRpc) {
 | 
	
		
			
				|  |  |    cli_ctx.AddMetadata(meta1.first, meta1.second);
 | 
	
		
			
				|  |  |    cli_ctx.AddMetadata(meta2.first, meta2.second);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
 | 
	
		
			
				|  |  | +  std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
 | 
	
		
			
				|  |  |        stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
 | 
	
	
		
			
				|  | @@ -519,7 +525,7 @@ TEST_P(AsyncEnd2endTest, ServerInitialMetadataRpc) {
 | 
	
		
			
				|  |  |    std::pair<grpc::string, grpc::string> meta1("key1", "val1");
 | 
	
		
			
				|  |  |    std::pair<grpc::string, grpc::string> meta2("key2", "val2");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
 | 
	
		
			
				|  |  | +  std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
 | 
	
		
			
				|  |  |        stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
 | 
	
	
		
			
				|  | @@ -568,7 +574,7 @@ TEST_P(AsyncEnd2endTest, ServerTrailingMetadataRpc) {
 | 
	
		
			
				|  |  |    std::pair<grpc::string, grpc::string> meta1("key1", "val1");
 | 
	
		
			
				|  |  |    std::pair<grpc::string, grpc::string> meta2("key2", "val2");
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
 | 
	
		
			
				|  |  | +  std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
 | 
	
		
			
				|  |  |        stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
 | 
	
	
		
			
				|  | @@ -629,7 +635,7 @@ TEST_P(AsyncEnd2endTest, MetadataRpc) {
 | 
	
		
			
				|  |  |    cli_ctx.AddMetadata(meta1.first, meta1.second);
 | 
	
		
			
				|  |  |    cli_ctx.AddMetadata(meta2.first, meta2.second);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
 | 
	
		
			
				|  |  | +  std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
 | 
	
		
			
				|  |  |        stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    service_.RequestEcho(&srv_ctx, &recv_request, &response_writer, cq_.get(),
 | 
	
	
		
			
				|  | @@ -690,7 +696,7 @@ TEST_P(AsyncEnd2endTest, ServerCheckCancellation) {
 | 
	
		
			
				|  |  |    grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    send_request.set_message("Hello");
 | 
	
		
			
				|  |  | -  std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
 | 
	
		
			
				|  |  | +  std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
 | 
	
		
			
				|  |  |        stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    srv_ctx.AsyncNotifyWhenDone(tag(5));
 | 
	
	
		
			
				|  | @@ -725,7 +731,7 @@ TEST_P(AsyncEnd2endTest, ServerCheckDone) {
 | 
	
		
			
				|  |  |    grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    send_request.set_message("Hello");
 | 
	
		
			
				|  |  | -  std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
 | 
	
		
			
				|  |  | +  std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
 | 
	
		
			
				|  |  |        stub_->AsyncEcho(&cli_ctx, send_request, cq_.get()));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    srv_ctx.AsyncNotifyWhenDone(tag(5));
 | 
	
	
		
			
				|  | @@ -759,7 +765,7 @@ TEST_P(AsyncEnd2endTest, UnimplementedRpc) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    ClientContext cli_ctx;
 | 
	
		
			
				|  |  |    send_request.set_message("Hello");
 | 
	
		
			
				|  |  | -  std::unique_ptr<ClientAsyncResponseReader<EchoResponse> > response_reader(
 | 
	
		
			
				|  |  | +  std::unique_ptr<ClientAsyncResponseReader<EchoResponse>> response_reader(
 | 
	
		
			
				|  |  |        stub->AsyncUnimplemented(&cli_ctx, send_request, cq_.get()));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    response_reader->Finish(&recv_response, &recv_status, tag(4));
 | 
	
	
		
			
				|  | @@ -769,8 +775,384 @@ TEST_P(AsyncEnd2endTest, UnimplementedRpc) {
 | 
	
		
			
				|  |  |    EXPECT_EQ("", recv_status.error_message());
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +// This class is for testing scenarios where RPCs are cancelled on the server
 | 
	
		
			
				|  |  | +// by calling ServerContext::TryCancel()
 | 
	
		
			
				|  |  | +class AsyncEnd2endServerTryCancelTest : public AsyncEnd2endTest {
 | 
	
		
			
				|  |  | + protected:
 | 
	
		
			
				|  |  | +  typedef enum {
 | 
	
		
			
				|  |  | +    DO_NOT_CANCEL = 0,
 | 
	
		
			
				|  |  | +    CANCEL_BEFORE_PROCESSING,
 | 
	
		
			
				|  |  | +    CANCEL_DURING_PROCESSING,
 | 
	
		
			
				|  |  | +    CANCEL_AFTER_PROCESSING
 | 
	
		
			
				|  |  | +  } ServerTryCancelRequestPhase;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  void ServerTryCancel(ServerContext* context) {
 | 
	
		
			
				|  |  | +    EXPECT_FALSE(context->IsCancelled());
 | 
	
		
			
				|  |  | +    context->TryCancel();
 | 
	
		
			
				|  |  | +    gpr_log(GPR_INFO, "Server called TryCancel()");
 | 
	
		
			
				|  |  | +    EXPECT_TRUE(context->IsCancelled());
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Helper for testing client-streaming RPCs which are cancelled on the server.
 | 
	
		
			
				|  |  | +  // Depending on the value of server_try_cancel parameter, this will test one
 | 
	
		
			
				|  |  | +  // of the following three scenarios:
 | 
	
		
			
				|  |  | +  //   CANCEL_BEFORE_PROCESSING: Rpc is cancelled by the server before reading
 | 
	
		
			
				|  |  | +  //   any messages from the client
 | 
	
		
			
				|  |  | +  //
 | 
	
		
			
				|  |  | +  //   CANCEL_DURING_PROCESSING: Rpc is cancelled by the server while reading
 | 
	
		
			
				|  |  | +  //   messages from the client
 | 
	
		
			
				|  |  | +  //
 | 
	
		
			
				|  |  | +  //   CANCEL_AFTER PROCESSING: Rpc is cancelled by server after reading all
 | 
	
		
			
				|  |  | +  //   messages from the client (but before sending any status back to the
 | 
	
		
			
				|  |  | +  //   client)
 | 
	
		
			
				|  |  | +  void TestClientStreamingServerCancel(
 | 
	
		
			
				|  |  | +      ServerTryCancelRequestPhase server_try_cancel) {
 | 
	
		
			
				|  |  | +    ResetStub();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    EchoRequest send_request;
 | 
	
		
			
				|  |  | +    EchoRequest recv_request;
 | 
	
		
			
				|  |  | +    EchoResponse send_response;
 | 
	
		
			
				|  |  | +    EchoResponse recv_response;
 | 
	
		
			
				|  |  | +    Status recv_status;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    ClientContext cli_ctx;
 | 
	
		
			
				|  |  | +    ServerContext srv_ctx;
 | 
	
		
			
				|  |  | +    ServerAsyncReader<EchoResponse, EchoRequest> srv_stream(&srv_ctx);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Initiate the 'RequestStream' call on client
 | 
	
		
			
				|  |  | +    std::unique_ptr<ClientAsyncWriter<EchoRequest>> cli_stream(
 | 
	
		
			
				|  |  | +        stub_->AsyncRequestStream(&cli_ctx, &recv_response, cq_.get(), tag(1)));
 | 
	
		
			
				|  |  | +    Verifier(GetParam()).Expect(1, true).Verify(cq_.get());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // On the server, request to be notified of 'RequestStream' calls
 | 
	
		
			
				|  |  | +    // and receive the 'RequestStream' call just made by the client
 | 
	
		
			
				|  |  | +    service_.RequestRequestStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(),
 | 
	
		
			
				|  |  | +                                  tag(2));
 | 
	
		
			
				|  |  | +    Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Client sends 3 messages (tags 3, 4 and 5)
 | 
	
		
			
				|  |  | +    for (int tag_idx = 3; tag_idx <= 5; tag_idx++) {
 | 
	
		
			
				|  |  | +      send_request.set_message("Ping " + std::to_string(tag_idx));
 | 
	
		
			
				|  |  | +      cli_stream->Write(send_request, tag(tag_idx));
 | 
	
		
			
				|  |  | +      Verifier(GetParam()).Expect(tag_idx, true).Verify(cq_.get());
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    cli_stream->WritesDone(tag(6));
 | 
	
		
			
				|  |  | +    Verifier(GetParam()).Expect(6, true).Verify(cq_.get());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    bool expected_server_cq_result = true;
 | 
	
		
			
				|  |  | +    bool ignore_cq_result = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (server_try_cancel == CANCEL_BEFORE_PROCESSING) {
 | 
	
		
			
				|  |  | +      ServerTryCancel(&srv_ctx);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // Since cancellation is done before server reads any results, we know
 | 
	
		
			
				|  |  | +      // for sure that all cq results will return false from this point forward
 | 
	
		
			
				|  |  | +      expected_server_cq_result = false;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    std::thread* server_try_cancel_thd = NULL;
 | 
	
		
			
				|  |  | +    if (server_try_cancel == CANCEL_DURING_PROCESSING) {
 | 
	
		
			
				|  |  | +      server_try_cancel_thd = new std::thread(
 | 
	
		
			
				|  |  | +          &AsyncEnd2endServerTryCancelTest::ServerTryCancel, this, &srv_ctx);
 | 
	
		
			
				|  |  | +      // Server will cancel the RPC in a parallel thread while reading the
 | 
	
		
			
				|  |  | +      // requests from the client. Since the cancellation can happen at anytime,
 | 
	
		
			
				|  |  | +      // some of the cq results (i.e those until cancellation) might be true but
 | 
	
		
			
				|  |  | +      // its non deterministic. So better to ignore the cq results
 | 
	
		
			
				|  |  | +      ignore_cq_result = true;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Server reads 3 messages (tags 6, 7 and 8)
 | 
	
		
			
				|  |  | +    for (int tag_idx = 6; tag_idx <= 8; tag_idx++) {
 | 
	
		
			
				|  |  | +      srv_stream.Read(&recv_request, tag(tag_idx));
 | 
	
		
			
				|  |  | +      Verifier(GetParam())
 | 
	
		
			
				|  |  | +          .Expect(tag_idx, expected_server_cq_result)
 | 
	
		
			
				|  |  | +          .Verify(cq_.get(), ignore_cq_result);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (server_try_cancel_thd != NULL) {
 | 
	
		
			
				|  |  | +      server_try_cancel_thd->join();
 | 
	
		
			
				|  |  | +      delete server_try_cancel_thd;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (server_try_cancel == CANCEL_AFTER_PROCESSING) {
 | 
	
		
			
				|  |  | +      ServerTryCancel(&srv_ctx);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // The RPC has been cancelled at this point for sure (i.e irrespective of
 | 
	
		
			
				|  |  | +    // the value of `server_try_cancel` is). So, from this point forward, we
 | 
	
		
			
				|  |  | +    // know that cq results are supposed to return false on server.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Server sends the final message and cancelled status (but the RPC is
 | 
	
		
			
				|  |  | +    // already cancelled at this point. So we expect the operation to fail)
 | 
	
		
			
				|  |  | +    srv_stream.Finish(send_response, Status::CANCELLED, tag(9));
 | 
	
		
			
				|  |  | +    Verifier(GetParam()).Expect(9, false).Verify(cq_.get());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Client will see the cancellation
 | 
	
		
			
				|  |  | +    cli_stream->Finish(&recv_status, tag(10));
 | 
	
		
			
				|  |  | +    // TODO(sreek): The expectation here should be true. This is a bug (github
 | 
	
		
			
				|  |  | +    // issue #4972)
 | 
	
		
			
				|  |  | +    Verifier(GetParam()).Expect(10, false).Verify(cq_.get());
 | 
	
		
			
				|  |  | +    EXPECT_FALSE(recv_status.ok());
 | 
	
		
			
				|  |  | +    EXPECT_EQ(::grpc::StatusCode::CANCELLED, recv_status.error_code());
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Helper for testing server-streaming RPCs which are cancelled on the server.
 | 
	
		
			
				|  |  | +  // Depending on the value of server_try_cancel parameter, this will test one
 | 
	
		
			
				|  |  | +  // of the following three scenarios:
 | 
	
		
			
				|  |  | +  //   CANCEL_BEFORE_PROCESSING: Rpc is cancelled by the server before sending
 | 
	
		
			
				|  |  | +  //   any messages to the client
 | 
	
		
			
				|  |  | +  //
 | 
	
		
			
				|  |  | +  //   CANCEL_DURING_PROCESSING: Rpc is cancelled by the server while sending
 | 
	
		
			
				|  |  | +  //   messages to the client
 | 
	
		
			
				|  |  | +  //
 | 
	
		
			
				|  |  | +  //   CANCEL_AFTER PROCESSING: Rpc is cancelled by server after sending all
 | 
	
		
			
				|  |  | +  //   messages to the client (but before sending any status back to the
 | 
	
		
			
				|  |  | +  //   client)
 | 
	
		
			
				|  |  | +  void TestServerStreamingServerCancel(
 | 
	
		
			
				|  |  | +      ServerTryCancelRequestPhase server_try_cancel) {
 | 
	
		
			
				|  |  | +    ResetStub();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    EchoRequest send_request;
 | 
	
		
			
				|  |  | +    EchoRequest recv_request;
 | 
	
		
			
				|  |  | +    EchoResponse send_response;
 | 
	
		
			
				|  |  | +    EchoResponse recv_response;
 | 
	
		
			
				|  |  | +    Status recv_status;
 | 
	
		
			
				|  |  | +    ClientContext cli_ctx;
 | 
	
		
			
				|  |  | +    ServerContext srv_ctx;
 | 
	
		
			
				|  |  | +    ServerAsyncWriter<EchoResponse> srv_stream(&srv_ctx);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    send_request.set_message("Ping");
 | 
	
		
			
				|  |  | +    // Initiate the 'ResponseStream' call on the client
 | 
	
		
			
				|  |  | +    std::unique_ptr<ClientAsyncReader<EchoResponse>> cli_stream(
 | 
	
		
			
				|  |  | +        stub_->AsyncResponseStream(&cli_ctx, send_request, cq_.get(), tag(1)));
 | 
	
		
			
				|  |  | +    Verifier(GetParam()).Expect(1, true).Verify(cq_.get());
 | 
	
		
			
				|  |  | +    // On the server, request to be notified of 'ResponseStream' calls and
 | 
	
		
			
				|  |  | +    // receive the call just made by the client
 | 
	
		
			
				|  |  | +    service_.RequestResponseStream(&srv_ctx, &recv_request, &srv_stream,
 | 
	
		
			
				|  |  | +                                   cq_.get(), cq_.get(), tag(2));
 | 
	
		
			
				|  |  | +    Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
 | 
	
		
			
				|  |  | +    EXPECT_EQ(send_request.message(), recv_request.message());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    bool expected_cq_result = true;
 | 
	
		
			
				|  |  | +    bool ignore_cq_result = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (server_try_cancel == CANCEL_BEFORE_PROCESSING) {
 | 
	
		
			
				|  |  | +      ServerTryCancel(&srv_ctx);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // We know for sure that all cq results will be false from this point
 | 
	
		
			
				|  |  | +      // since the server cancelled the RPC
 | 
	
		
			
				|  |  | +      expected_cq_result = false;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    std::thread* server_try_cancel_thd = NULL;
 | 
	
		
			
				|  |  | +    if (server_try_cancel == CANCEL_DURING_PROCESSING) {
 | 
	
		
			
				|  |  | +      server_try_cancel_thd = new std::thread(
 | 
	
		
			
				|  |  | +          &AsyncEnd2endServerTryCancelTest::ServerTryCancel, this, &srv_ctx);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // Server will cancel the RPC in a parallel thread while writing responses
 | 
	
		
			
				|  |  | +      // to the client. Since the cancellation can happen at anytime, some of
 | 
	
		
			
				|  |  | +      // the cq results (i.e those until cancellation) might be true but it is
 | 
	
		
			
				|  |  | +      // non deterministic. So better to ignore the cq results
 | 
	
		
			
				|  |  | +      ignore_cq_result = true;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Server sends three messages (tags 3, 4 and 5)
 | 
	
		
			
				|  |  | +    for (int tag_idx = 3; tag_idx <= 5; tag_idx++) {
 | 
	
		
			
				|  |  | +      send_response.set_message("Pong " + std::to_string(tag_idx));
 | 
	
		
			
				|  |  | +      srv_stream.Write(send_response, tag(tag_idx));
 | 
	
		
			
				|  |  | +      Verifier(GetParam())
 | 
	
		
			
				|  |  | +          .Expect(tag_idx, expected_cq_result)
 | 
	
		
			
				|  |  | +          .Verify(cq_.get(), ignore_cq_result);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (server_try_cancel_thd != NULL) {
 | 
	
		
			
				|  |  | +      server_try_cancel_thd->join();
 | 
	
		
			
				|  |  | +      delete server_try_cancel_thd;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (server_try_cancel == CANCEL_AFTER_PROCESSING) {
 | 
	
		
			
				|  |  | +      ServerTryCancel(&srv_ctx);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Client attemts to read the three messages from the server
 | 
	
		
			
				|  |  | +    for (int tag_idx = 6; tag_idx <= 8; tag_idx++) {
 | 
	
		
			
				|  |  | +      cli_stream->Read(&recv_response, tag(tag_idx));
 | 
	
		
			
				|  |  | +      Verifier(GetParam())
 | 
	
		
			
				|  |  | +          .Expect(tag_idx, expected_cq_result)
 | 
	
		
			
				|  |  | +          .Verify(cq_.get(), ignore_cq_result);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // The RPC has been cancelled at this point for sure (i.e irrespective of
 | 
	
		
			
				|  |  | +    // the value of `server_try_cancel` is). So, from this point forward, we
 | 
	
		
			
				|  |  | +    // know that cq results are supposed to return false on server.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Server finishes the stream (but the RPC is already cancelled)
 | 
	
		
			
				|  |  | +    srv_stream.Finish(Status::CANCELLED, tag(9));
 | 
	
		
			
				|  |  | +    Verifier(GetParam()).Expect(9, false).Verify(cq_.get());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Client will see the cancellation
 | 
	
		
			
				|  |  | +    cli_stream->Finish(&recv_status, tag(10));
 | 
	
		
			
				|  |  | +    Verifier(GetParam()).Expect(10, true).Verify(cq_.get());
 | 
	
		
			
				|  |  | +    EXPECT_FALSE(recv_status.ok());
 | 
	
		
			
				|  |  | +    EXPECT_EQ(::grpc::StatusCode::CANCELLED, recv_status.error_code());
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // Helper for testing bidirectinal-streaming RPCs which are cancelled on the
 | 
	
		
			
				|  |  | +  // server.
 | 
	
		
			
				|  |  | +  //
 | 
	
		
			
				|  |  | +  // Depending on the value of server_try_cancel parameter, this will
 | 
	
		
			
				|  |  | +  // test one of the following three scenarios:
 | 
	
		
			
				|  |  | +  //   CANCEL_BEFORE_PROCESSING: Rpc is cancelled by the server before reading/
 | 
	
		
			
				|  |  | +  //   writing any messages from/to the client
 | 
	
		
			
				|  |  | +  //
 | 
	
		
			
				|  |  | +  //   CANCEL_DURING_PROCESSING: Rpc is cancelled by the server while reading
 | 
	
		
			
				|  |  | +  //   messages from the client
 | 
	
		
			
				|  |  | +  //
 | 
	
		
			
				|  |  | +  //   CANCEL_AFTER PROCESSING: Rpc is cancelled by server after reading all
 | 
	
		
			
				|  |  | +  //   messages from the client (but before sending any status back to the
 | 
	
		
			
				|  |  | +  //   client)
 | 
	
		
			
				|  |  | +  void TestBidiStreamingServerCancel(
 | 
	
		
			
				|  |  | +      ServerTryCancelRequestPhase server_try_cancel) {
 | 
	
		
			
				|  |  | +    ResetStub();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    EchoRequest send_request;
 | 
	
		
			
				|  |  | +    EchoRequest recv_request;
 | 
	
		
			
				|  |  | +    EchoResponse send_response;
 | 
	
		
			
				|  |  | +    EchoResponse recv_response;
 | 
	
		
			
				|  |  | +    Status recv_status;
 | 
	
		
			
				|  |  | +    ClientContext cli_ctx;
 | 
	
		
			
				|  |  | +    ServerContext srv_ctx;
 | 
	
		
			
				|  |  | +    ServerAsyncReaderWriter<EchoResponse, EchoRequest> srv_stream(&srv_ctx);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Initiate the call from the client side
 | 
	
		
			
				|  |  | +    std::unique_ptr<ClientAsyncReaderWriter<EchoRequest, EchoResponse>>
 | 
	
		
			
				|  |  | +        cli_stream(stub_->AsyncBidiStream(&cli_ctx, cq_.get(), tag(1)));
 | 
	
		
			
				|  |  | +    Verifier(GetParam()).Expect(1, true).Verify(cq_.get());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // On the server, request to be notified of the 'BidiStream' call and
 | 
	
		
			
				|  |  | +    // receive the call just made by the client
 | 
	
		
			
				|  |  | +    service_.RequestBidiStream(&srv_ctx, &srv_stream, cq_.get(), cq_.get(),
 | 
	
		
			
				|  |  | +                               tag(2));
 | 
	
		
			
				|  |  | +    Verifier(GetParam()).Expect(2, true).Verify(cq_.get());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Client sends the first and the only message
 | 
	
		
			
				|  |  | +    send_request.set_message("Ping");
 | 
	
		
			
				|  |  | +    cli_stream->Write(send_request, tag(3));
 | 
	
		
			
				|  |  | +    Verifier(GetParam()).Expect(3, true).Verify(cq_.get());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    bool expected_cq_result = true;
 | 
	
		
			
				|  |  | +    bool ignore_cq_result = false;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (server_try_cancel == CANCEL_BEFORE_PROCESSING) {
 | 
	
		
			
				|  |  | +      ServerTryCancel(&srv_ctx);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // We know for sure that all cq results will be false from this point
 | 
	
		
			
				|  |  | +      // since the server cancelled the RPC
 | 
	
		
			
				|  |  | +      expected_cq_result = false;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    std::thread* server_try_cancel_thd = NULL;
 | 
	
		
			
				|  |  | +    if (server_try_cancel == CANCEL_DURING_PROCESSING) {
 | 
	
		
			
				|  |  | +      server_try_cancel_thd = new std::thread(
 | 
	
		
			
				|  |  | +          &AsyncEnd2endServerTryCancelTest::ServerTryCancel, this, &srv_ctx);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      // Since server is going to cancel the RPC in a parallel thread, some of
 | 
	
		
			
				|  |  | +      // the cq results (i.e those until the cancellation) might be true. Since
 | 
	
		
			
				|  |  | +      // that number is non-deterministic, it is better to ignore the cq results
 | 
	
		
			
				|  |  | +      ignore_cq_result = true;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    srv_stream.Read(&recv_request, tag(4));
 | 
	
		
			
				|  |  | +    Verifier(GetParam())
 | 
	
		
			
				|  |  | +        .Expect(4, expected_cq_result)
 | 
	
		
			
				|  |  | +        .Verify(cq_.get(), ignore_cq_result);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    send_response.set_message("Pong");
 | 
	
		
			
				|  |  | +    srv_stream.Write(send_response, tag(5));
 | 
	
		
			
				|  |  | +    Verifier(GetParam())
 | 
	
		
			
				|  |  | +        .Expect(5, expected_cq_result)
 | 
	
		
			
				|  |  | +        .Verify(cq_.get(), ignore_cq_result);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    cli_stream->Read(&recv_response, tag(6));
 | 
	
		
			
				|  |  | +    Verifier(GetParam())
 | 
	
		
			
				|  |  | +        .Expect(6, expected_cq_result)
 | 
	
		
			
				|  |  | +        .Verify(cq_.get(), ignore_cq_result);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // This is expected to succeed in all cases
 | 
	
		
			
				|  |  | +    cli_stream->WritesDone(tag(7));
 | 
	
		
			
				|  |  | +    Verifier(GetParam()).Expect(7, true).Verify(cq_.get());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // This is expected to fail in all cases i.e for all values of
 | 
	
		
			
				|  |  | +    // server_try_cancel. This is becasue at this point, either there are no
 | 
	
		
			
				|  |  | +    // more msgs from the client (because client called WritesDone) or the RPC
 | 
	
		
			
				|  |  | +    // is cancelled on the server
 | 
	
		
			
				|  |  | +    srv_stream.Read(&recv_request, tag(8));
 | 
	
		
			
				|  |  | +    Verifier(GetParam()).Expect(8, false).Verify(cq_.get());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (server_try_cancel_thd != NULL) {
 | 
	
		
			
				|  |  | +      server_try_cancel_thd->join();
 | 
	
		
			
				|  |  | +      delete server_try_cancel_thd;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (server_try_cancel == CANCEL_AFTER_PROCESSING) {
 | 
	
		
			
				|  |  | +      ServerTryCancel(&srv_ctx);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // The RPC has been cancelled at this point for sure (i.e irrespective of
 | 
	
		
			
				|  |  | +    // the value of `server_try_cancel` is). So, from this point forward, we
 | 
	
		
			
				|  |  | +    // know that cq results are supposed to return false on server.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    srv_stream.Finish(Status::CANCELLED, tag(9));
 | 
	
		
			
				|  |  | +    Verifier(GetParam()).Expect(9, false).Verify(cq_.get());
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    cli_stream->Finish(&recv_status, tag(10));
 | 
	
		
			
				|  |  | +    Verifier(GetParam()).Expect(10, true).Verify(cq_.get());
 | 
	
		
			
				|  |  | +    EXPECT_FALSE(recv_status.ok());
 | 
	
		
			
				|  |  | +    EXPECT_EQ(grpc::StatusCode::CANCELLED, recv_status.error_code());
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +TEST_P(AsyncEnd2endServerTryCancelTest, ClientStreamingServerTryCancelBefore) {
 | 
	
		
			
				|  |  | +  TestClientStreamingServerCancel(CANCEL_BEFORE_PROCESSING);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +TEST_P(AsyncEnd2endServerTryCancelTest, ClientStreamingServerTryCancelDuring) {
 | 
	
		
			
				|  |  | +  TestClientStreamingServerCancel(CANCEL_DURING_PROCESSING);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +TEST_P(AsyncEnd2endServerTryCancelTest, ClientStreamingServerTryCancelAfter) {
 | 
	
		
			
				|  |  | +  TestClientStreamingServerCancel(CANCEL_AFTER_PROCESSING);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +TEST_P(AsyncEnd2endServerTryCancelTest, ServerStreamingServerTryCancelBefore) {
 | 
	
		
			
				|  |  | +  TestServerStreamingServerCancel(CANCEL_BEFORE_PROCESSING);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +TEST_P(AsyncEnd2endServerTryCancelTest, ServerStreamingServerTryCancelDuring) {
 | 
	
		
			
				|  |  | +  TestServerStreamingServerCancel(CANCEL_DURING_PROCESSING);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +TEST_P(AsyncEnd2endServerTryCancelTest, ServerStreamingServerTryCancelAfter) {
 | 
	
		
			
				|  |  | +  TestServerStreamingServerCancel(CANCEL_AFTER_PROCESSING);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +TEST_P(AsyncEnd2endServerTryCancelTest, ServerBidiStreamingTryCancelBefore) {
 | 
	
		
			
				|  |  | +  TestBidiStreamingServerCancel(CANCEL_BEFORE_PROCESSING);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +TEST_P(AsyncEnd2endServerTryCancelTest, ServerBidiStreamingTryCancelDuring) {
 | 
	
		
			
				|  |  | +  TestBidiStreamingServerCancel(CANCEL_DURING_PROCESSING);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +TEST_P(AsyncEnd2endServerTryCancelTest, ServerBidiStreamingTryCancelAfter) {
 | 
	
		
			
				|  |  | +  TestBidiStreamingServerCancel(CANCEL_AFTER_PROCESSING);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  INSTANTIATE_TEST_CASE_P(AsyncEnd2end, AsyncEnd2endTest,
 | 
	
		
			
				|  |  |                          ::testing::Values(false, true));
 | 
	
		
			
				|  |  | +INSTANTIATE_TEST_CASE_P(AsyncEnd2endServerTryCancel,
 | 
	
		
			
				|  |  | +                        AsyncEnd2endServerTryCancelTest,
 | 
	
		
			
				|  |  | +                        ::testing::Values(false));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  }  // namespace
 | 
	
		
			
				|  |  |  }  // namespace testing
 |