|
|
|
@ -472,7 +472,7 @@ describe 'ClientStub' do |
|
|
|
|
host = "localhost:#{server_port}" |
|
|
|
|
stub = GRPC::ClientStub.new(host, :this_channel_is_insecure) |
|
|
|
|
expect do |
|
|
|
|
get_responses(stub) |
|
|
|
|
get_responses(stub).collect { |r| r } |
|
|
|
|
end.to raise_error(ArgumentError, |
|
|
|
|
/Header values must be of type string or array/) |
|
|
|
|
end |
|
|
|
@ -641,11 +641,101 @@ describe 'ClientStub' do |
|
|
|
|
expect(e.collect { |r| r }).to eq(@sent_msgs) |
|
|
|
|
th.join |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
# Prompted by grpc/github #10526 |
|
|
|
|
describe 'surfacing of errors when sending requests' do |
|
|
|
|
def run_server_bidi_send_one_then_read_indefinitely |
|
|
|
|
@server.start |
|
|
|
|
recvd_rpc = @server.request_call |
|
|
|
|
recvd_call = recvd_rpc.call |
|
|
|
|
server_call = GRPC::ActiveCall.new( |
|
|
|
|
recvd_call, noop, noop, INFINITE_FUTURE, |
|
|
|
|
metadata_received: true, started: false) |
|
|
|
|
server_call.send_initial_metadata |
|
|
|
|
server_call.remote_send('server response') |
|
|
|
|
loop do |
|
|
|
|
m = server_call.remote_read |
|
|
|
|
break if m.nil? |
|
|
|
|
end |
|
|
|
|
# can't fail since initial metadata already sent |
|
|
|
|
server_call.send_status(@pass, 'OK', true) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def verify_error_from_write_thread(stub, requests_to_push, |
|
|
|
|
request_queue, expected_description) |
|
|
|
|
# TODO: an improvement might be to raise the original exception from |
|
|
|
|
# bidi call write loops instead of only cancelling the call |
|
|
|
|
failing_marshal_proc = proc do |req| |
|
|
|
|
fail req if req.is_a?(StandardError) |
|
|
|
|
req |
|
|
|
|
end |
|
|
|
|
begin |
|
|
|
|
e = get_responses(stub, marshal_proc: failing_marshal_proc) |
|
|
|
|
first_response = e.next |
|
|
|
|
expect(first_response).to eq('server response') |
|
|
|
|
requests_to_push.each { |req| request_queue.push(req) } |
|
|
|
|
e.collect { |r| r } |
|
|
|
|
rescue GRPC::Unknown => e |
|
|
|
|
exception = e |
|
|
|
|
end |
|
|
|
|
expect(exception.message.include?(expected_description)).to be(true) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
# Provides an Enumerable view of a Queue |
|
|
|
|
class BidiErrorTestingEnumerateForeverQueue |
|
|
|
|
def initialize(queue) |
|
|
|
|
@queue = queue |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def each |
|
|
|
|
loop do |
|
|
|
|
msg = @queue.pop |
|
|
|
|
yield msg |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def run_error_in_client_request_stream_test(requests_to_push, |
|
|
|
|
expected_error_message) |
|
|
|
|
# start a server that waits on a read indefinitely - it should |
|
|
|
|
# see a cancellation and be able to break out |
|
|
|
|
th = Thread.new { run_server_bidi_send_one_then_read_indefinitely } |
|
|
|
|
stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure) |
|
|
|
|
|
|
|
|
|
request_queue = Queue.new |
|
|
|
|
@sent_msgs = BidiErrorTestingEnumerateForeverQueue.new(request_queue) |
|
|
|
|
|
|
|
|
|
verify_error_from_write_thread(stub, |
|
|
|
|
requests_to_push, |
|
|
|
|
request_queue, |
|
|
|
|
expected_error_message) |
|
|
|
|
# the write loop errror should cancel the call and end the |
|
|
|
|
# server's request stream |
|
|
|
|
th.join |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
it 'non-GRPC errors from the write loop surface when raised ' \ |
|
|
|
|
'at the start of a request stream' do |
|
|
|
|
expected_error_message = 'expect error on first request' |
|
|
|
|
requests_to_push = [StandardError.new(expected_error_message)] |
|
|
|
|
run_error_in_client_request_stream_test(requests_to_push, |
|
|
|
|
expected_error_message) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
it 'non-GRPC errors from the write loop surface when raised ' \ |
|
|
|
|
'during the middle of a request stream' do |
|
|
|
|
expected_error_message = 'expect error on last request' |
|
|
|
|
requests_to_push = %w( one two ) |
|
|
|
|
requests_to_push << StandardError.new(expected_error_message) |
|
|
|
|
run_error_in_client_request_stream_test(requests_to_push, |
|
|
|
|
expected_error_message) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
describe 'without a call operation' do |
|
|
|
|
def get_responses(stub, deadline: nil) |
|
|
|
|
e = stub.bidi_streamer(@method, @sent_msgs, noop, noop, |
|
|
|
|
def get_responses(stub, deadline: nil, marshal_proc: noop) |
|
|
|
|
e = stub.bidi_streamer(@method, @sent_msgs, marshal_proc, noop, |
|
|
|
|
metadata: @metadata, deadline: deadline) |
|
|
|
|
expect(e).to be_a(Enumerator) |
|
|
|
|
e |
|
|
|
@ -658,8 +748,9 @@ describe 'ClientStub' do |
|
|
|
|
after(:each) do |
|
|
|
|
@op.wait # make sure wait doesn't hang |
|
|
|
|
end |
|
|
|
|
def get_responses(stub, run_start_call_first: false, deadline: nil) |
|
|
|
|
@op = stub.bidi_streamer(@method, @sent_msgs, noop, noop, |
|
|
|
|
def get_responses(stub, run_start_call_first: false, deadline: nil, |
|
|
|
|
marshal_proc: noop) |
|
|
|
|
@op = stub.bidi_streamer(@method, @sent_msgs, marshal_proc, noop, |
|
|
|
|
return_op: true, |
|
|
|
|
metadata: @metadata, deadline: deadline) |
|
|
|
|
expect(@op).to be_a(GRPC::ActiveCall::Operation) |
|
|
|
|