From 09600be0a56774d11fd575b5a80a1e8cfc7d13a2 Mon Sep 17 00:00:00 2001
From: Craig Tiller <craig.tiller@gmail.com>
Date: Wed, 13 May 2015 16:46:55 -0700
Subject: [PATCH] Ensure that there's always a poller for completion

The C core uses completion_queue_next as a directive that progress should be made on requests bound to that cq.
If nobody is polling for completion, then a deadlock can occur (client needs to do work, but we're blocked waiting for the server).
There is no scope for this to occur using the idiomatic layers (as far as I can tell), but these low level tests need to be massaged.
---
 src/ruby/spec/client_server_spec.rb | 60 +++++++++++++++++++++++++----
 1 file changed, 52 insertions(+), 8 deletions(-)

diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb
index 68af79f907..b247882241 100644
--- a/src/ruby/spec/client_server_spec.rb
+++ b/src/ruby/spec/client_server_spec.rb
@@ -74,6 +74,12 @@ shared_examples 'basic GRPC message delivery is OK' do
 
   it 'servers receive requests from clients and can respond' do
     call = new_client_call
+    server_call = nil
+
+    server_thread = Thread.new do
+      server_call = server_allows_client_to_proceed
+    end
+
     client_ops = {
       CallOps::SEND_INITIAL_METADATA => {},
       CallOps::SEND_MESSAGE => sent_message
@@ -84,7 +90,7 @@ shared_examples 'basic GRPC message delivery is OK' do
     expect(batch_result.send_message).to be true
 
     # confirm the server can read the inbound message
-    server_call = server_allows_client_to_proceed
+    server_thread.join
     server_ops = {
       CallOps::RECV_MESSAGE => nil
     }
@@ -95,6 +101,12 @@ shared_examples 'basic GRPC message delivery is OK' do
 
   it 'responses written by servers are received by the client' do
     call = new_client_call
+    server_call = nil
+
+    server_thread = Thread.new do
+      server_call = server_allows_client_to_proceed
+    end
+
     client_ops = {
       CallOps::SEND_INITIAL_METADATA => {},
       CallOps::SEND_MESSAGE => sent_message
@@ -105,7 +117,7 @@ shared_examples 'basic GRPC message delivery is OK' do
     expect(batch_result.send_message).to be true
 
     # confirm the server can read the inbound message
-    server_call = server_allows_client_to_proceed
+    server_thread.join
     server_ops = {
       CallOps::RECV_MESSAGE => nil,
       CallOps::SEND_MESSAGE => reply_text
@@ -118,6 +130,12 @@ shared_examples 'basic GRPC message delivery is OK' do
 
   it 'servers can ignore a client write and send a status' do
     call = new_client_call
+    server_call = nil
+
+    server_thread = Thread.new do
+      server_call = server_allows_client_to_proceed
+    end
+
     client_ops = {
       CallOps::SEND_INITIAL_METADATA => {},
       CallOps::SEND_MESSAGE => sent_message
@@ -129,7 +147,7 @@ shared_examples 'basic GRPC message delivery is OK' do
 
     # confirm the server can read the inbound message
     the_status = Struct::Status.new(StatusCodes::OK, 'OK')
-    server_call = server_allows_client_to_proceed
+    server_thread.join
     server_ops = {
       CallOps::SEND_STATUS_FROM_SERVER => the_status
     }
@@ -141,6 +159,12 @@ shared_examples 'basic GRPC message delivery is OK' do
 
   it 'completes calls by sending status to client and server' do
     call = new_client_call
+    server_call = nil
+
+    server_thread = Thread.new do
+      server_call = server_allows_client_to_proceed
+    end
+
     client_ops = {
       CallOps::SEND_INITIAL_METADATA => {},
       CallOps::SEND_MESSAGE => sent_message
@@ -152,7 +176,7 @@ shared_examples 'basic GRPC message delivery is OK' do
 
     # confirm the server can read the inbound message and respond
     the_status = Struct::Status.new(StatusCodes::OK, 'OK', {})
-    server_call = server_allows_client_to_proceed
+    server_thread.join
     server_ops = {
       CallOps::RECV_MESSAGE => nil,
       CallOps::SEND_MESSAGE => reply_text,
@@ -221,6 +245,11 @@ shared_examples 'GRPC metadata delivery works OK' do
 
     it 'sends all the metadata pairs when keys and values are valid' do
       @valid_metadata.each do |md|
+        recvd_rpc = nil
+        rcv_thread = Thread.new do
+          recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+        end
+
         call = new_client_call
         client_ops = {
           CallOps::SEND_INITIAL_METADATA => md
@@ -230,7 +259,7 @@ shared_examples 'GRPC metadata delivery works OK' do
         expect(batch_result.send_metadata).to be true
 
         # confirm the server can receive the client metadata
-        recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+        rcv_thread.join
         expect(recvd_rpc).to_not eq nil
         recvd_md = recvd_rpc.metadata
         replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }]
@@ -257,6 +286,11 @@ shared_examples 'GRPC metadata delivery works OK' do
 
     it 'raises an exception if a metadata key is invalid' do
       @bad_keys.each do |md|
+        recvd_rpc = nil
+        rcv_thread = Thread.new do
+          recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+        end
+
         call = new_client_call
         # client signals that it's done sending metadata to allow server to
         # respond
@@ -266,7 +300,7 @@ shared_examples 'GRPC metadata delivery works OK' do
         call.run_batch(@client_queue, @client_tag, deadline, client_ops)
 
         # server gets the invocation
-        recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+        rcv_thread.join
         expect(recvd_rpc).to_not eq nil
         server_ops = {
           CallOps::SEND_INITIAL_METADATA => md
@@ -280,6 +314,11 @@ shared_examples 'GRPC metadata delivery works OK' do
     end
 
     it 'sends an empty hash if no metadata is added' do
+      recvd_rpc = nil
+      rcv_thread = Thread.new do
+        recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+      end
+
       call = new_client_call
       # client signals that it's done sending metadata to allow server to
       # respond
@@ -289,7 +328,7 @@ shared_examples 'GRPC metadata delivery works OK' do
       call.run_batch(@client_queue, @client_tag, deadline, client_ops)
 
       # server gets the invocation but sends no metadata back
-      recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+      rcv_thread.join
       expect(recvd_rpc).to_not eq nil
       server_call = recvd_rpc.call
       server_ops = {
@@ -308,6 +347,11 @@ shared_examples 'GRPC metadata delivery works OK' do
 
     it 'sends all the pairs when keys and values are valid' do
       @valid_metadata.each do |md|
+        recvd_rpc = nil
+        rcv_thread = Thread.new do
+          recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+        end
+
         call = new_client_call
         # client signals that it's done sending metadata to allow server to
         # respond
@@ -317,7 +361,7 @@ shared_examples 'GRPC metadata delivery works OK' do
         call.run_batch(@client_queue, @client_tag, deadline, client_ops)
 
         # server gets the invocation but sends no metadata back
-        recvd_rpc = @server.request_call(@server_queue, @server_tag, deadline)
+        rcv_thread.join
         expect(recvd_rpc).to_not eq nil
         server_call = recvd_rpc.call
         server_ops = {
-- 
GitLab