|
|
|
@ -60,8 +60,10 @@ describe GRPC::ActiveCall do |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
describe '#multi_req_view' do |
|
|
|
|
it 'exposes a fixed subset of the ActiveCall methods' do |
|
|
|
|
want = %w(cancelled?, deadline, each_remote_read, metadata, shutdown) |
|
|
|
|
it 'exposes a fixed subset of the ActiveCall.methods' do |
|
|
|
|
want = %w(cancelled?, deadline, each_remote_read, metadata, \ |
|
|
|
|
shutdown, peer, peer_cert, send_initial_metadata, \ |
|
|
|
|
initial_metadata_sent) |
|
|
|
|
v = @client_call.multi_req_view |
|
|
|
|
want.each do |w| |
|
|
|
|
expect(v.methods.include?(w)) |
|
|
|
@ -70,8 +72,10 @@ describe GRPC::ActiveCall do |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
describe '#single_req_view' do |
|
|
|
|
it 'exposes a fixed subset of the ActiveCall methods' do |
|
|
|
|
want = %w(cancelled?, deadline, metadata, shutdown) |
|
|
|
|
it 'exposes a fixed subset of the ActiveCall.methods' do |
|
|
|
|
want = %w(cancelled?, deadline, metadata, shutdown, \ |
|
|
|
|
send_initial_metadata, metadata_to_send, \ |
|
|
|
|
merge_metadata_to_send, initial_metadata_sent) |
|
|
|
|
v = @client_call.single_req_view |
|
|
|
|
want.each do |w| |
|
|
|
|
expect(v.methods.include?(w)) |
|
|
|
@ -149,6 +153,158 @@ describe GRPC::ActiveCall do |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
describe 'sending initial metadata', send_initial_metadata: true do |
|
|
|
|
it 'sends metadata before sending a message if it hasnt been sent yet' do |
|
|
|
|
call = make_test_call |
|
|
|
|
@client_call = ActiveCall.new( |
|
|
|
|
call, |
|
|
|
|
@pass_through, |
|
|
|
|
@pass_through, |
|
|
|
|
deadline, |
|
|
|
|
started: false) |
|
|
|
|
|
|
|
|
|
metadata = { key: 'dummy_val', other: 'other_val' } |
|
|
|
|
expect(@client_call.metadata_sent).to eq(false) |
|
|
|
|
@client_call.merge_metadata_to_send(metadata) |
|
|
|
|
|
|
|
|
|
message = 'dummy message' |
|
|
|
|
|
|
|
|
|
expect(call).to( |
|
|
|
|
receive(:run_batch) |
|
|
|
|
.with( |
|
|
|
|
hash_including( |
|
|
|
|
CallOps::SEND_INITIAL_METADATA => metadata)).once) |
|
|
|
|
|
|
|
|
|
expect(call).to( |
|
|
|
|
receive(:run_batch).with(hash_including( |
|
|
|
|
CallOps::SEND_MESSAGE => message)).once) |
|
|
|
|
@client_call.remote_send(message) |
|
|
|
|
|
|
|
|
|
expect(@client_call.metadata_sent).to eq(true) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
it 'doesnt send metadata if it thinks its already been sent' do |
|
|
|
|
call = make_test_call |
|
|
|
|
|
|
|
|
|
@client_call = ActiveCall.new(call, |
|
|
|
|
@pass_through, |
|
|
|
|
@pass_through, |
|
|
|
|
deadline) |
|
|
|
|
|
|
|
|
|
expect(@client_call.metadata_sent).to eql(true) |
|
|
|
|
expect(call).to( |
|
|
|
|
receive(:run_batch).with(hash_including( |
|
|
|
|
CallOps::SEND_INITIAL_METADATA)).never) |
|
|
|
|
|
|
|
|
|
@client_call.remote_send('test message') |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
it 'sends metadata if it is explicitly sent and ok to do so' do |
|
|
|
|
call = make_test_call |
|
|
|
|
|
|
|
|
|
@client_call = ActiveCall.new(call, |
|
|
|
|
@pass_through, |
|
|
|
|
@pass_through, |
|
|
|
|
deadline, |
|
|
|
|
started: false) |
|
|
|
|
|
|
|
|
|
expect(@client_call.metadata_sent).to eql(false) |
|
|
|
|
|
|
|
|
|
metadata = { test_key: 'val' } |
|
|
|
|
@client_call.merge_metadata_to_send(metadata) |
|
|
|
|
expect(@client_call.metadata_to_send).to eq(metadata) |
|
|
|
|
|
|
|
|
|
expect(call).to( |
|
|
|
|
receive(:run_batch).with(hash_including( |
|
|
|
|
CallOps::SEND_INITIAL_METADATA => |
|
|
|
|
metadata)).once) |
|
|
|
|
@client_call.send_initial_metadata |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
it 'explicit sending fails if metadata has already been sent' do |
|
|
|
|
call = make_test_call |
|
|
|
|
|
|
|
|
|
@client_call = ActiveCall.new(call, |
|
|
|
|
@pass_through, |
|
|
|
|
@pass_through, |
|
|
|
|
deadline) |
|
|
|
|
|
|
|
|
|
expect(@client_call.metadata_sent).to eql(true) |
|
|
|
|
|
|
|
|
|
blk = proc do |
|
|
|
|
@client_call.send_initial_metadata |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
expect { blk.call }.to raise_error |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
describe '#merge_metadata_to_send', merge_metadata_to_send: true do |
|
|
|
|
it 'adds to existing metadata when there is existing metadata to send' do |
|
|
|
|
call = make_test_call |
|
|
|
|
starting_metadata = { k1: 'key1_val', k2: 'key2_val' } |
|
|
|
|
@client_call = ActiveCall.new( |
|
|
|
|
call, |
|
|
|
|
@pass_through, @pass_through, |
|
|
|
|
deadline, |
|
|
|
|
started: false, |
|
|
|
|
metadata_to_send: starting_metadata) |
|
|
|
|
|
|
|
|
|
expect(@client_call.metadata_to_send).to eq(starting_metadata) |
|
|
|
|
|
|
|
|
|
@client_call.merge_metadata_to_send( |
|
|
|
|
k3: 'key3_val', |
|
|
|
|
k4: 'key4_val') |
|
|
|
|
|
|
|
|
|
expected_md_to_send = { |
|
|
|
|
k1: 'key1_val', |
|
|
|
|
k2: 'key2_val', |
|
|
|
|
k3: 'key3_val', |
|
|
|
|
k4: 'key4_val' } |
|
|
|
|
|
|
|
|
|
expect(@client_call.metadata_to_send).to eq(expected_md_to_send) |
|
|
|
|
|
|
|
|
|
@client_call.merge_metadata_to_send(k5: 'key5_val') |
|
|
|
|
expected_md_to_send.merge!(k5: 'key5_val') |
|
|
|
|
expect(@client_call.metadata_to_send).to eq(expected_md_to_send) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
it 'overrides existing metadata if adding metadata with an existing key' do |
|
|
|
|
call = make_test_call |
|
|
|
|
starting_metadata = { k1: 'key1_val', k2: 'key2_val' } |
|
|
|
|
@client_call = ActiveCall.new( |
|
|
|
|
call, |
|
|
|
|
@pass_through, |
|
|
|
|
@pass_through, |
|
|
|
|
deadline, |
|
|
|
|
started: false, |
|
|
|
|
metadata_to_send: starting_metadata) |
|
|
|
|
|
|
|
|
|
expect(@client_call.metadata_to_send).to eq(starting_metadata) |
|
|
|
|
@client_call.merge_metadata_to_send(k1: 'key1_new_val') |
|
|
|
|
expect(@client_call.metadata_to_send).to eq(k1: 'key1_new_val', |
|
|
|
|
k2: 'key2_val') |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
it 'fails when initial metadata has already been sent' do |
|
|
|
|
call = make_test_call |
|
|
|
|
@client_call = ActiveCall.new( |
|
|
|
|
call, |
|
|
|
|
@pass_through, |
|
|
|
|
@pass_through, |
|
|
|
|
deadline, |
|
|
|
|
started: true) |
|
|
|
|
|
|
|
|
|
expect(@client_call.metadata_sent).to eq(true) |
|
|
|
|
|
|
|
|
|
blk = proc do |
|
|
|
|
@client_call.merge_metadata_to_send(k1: 'key1_val') |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
expect { blk.call }.to raise_error |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
describe '#client_invoke' do |
|
|
|
|
it 'sends metadata to the server when present' do |
|
|
|
|
call = make_test_call |
|
|
|
@ -163,7 +319,26 @@ describe GRPC::ActiveCall do |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
describe '#remote_read' do |
|
|
|
|
describe '#send_status', send_status: true do |
|
|
|
|
it 'works when no metadata or messages have been sent yet' do |
|
|
|
|
call = make_test_call |
|
|
|
|
ActiveCall.client_invoke(call) |
|
|
|
|
|
|
|
|
|
recvd_rpc = @server.request_call |
|
|
|
|
server_call = ActiveCall.new( |
|
|
|
|
recvd_rpc.call, |
|
|
|
|
@pass_through, |
|
|
|
|
@pass_through, |
|
|
|
|
deadline, |
|
|
|
|
started: false) |
|
|
|
|
|
|
|
|
|
expect(server_call.metadata_sent).to eq(false) |
|
|
|
|
blk = proc { server_call.send_status(OK) } |
|
|
|
|
expect { blk.call }.to_not raise_error |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
describe '#remote_read', remote_read: true do |
|
|
|
|
it 'reads the response sent by a server' do |
|
|
|
|
call = make_test_call |
|
|
|
|
ActiveCall.client_invoke(call) |
|
|
|
@ -205,6 +380,31 @@ describe GRPC::ActiveCall do |
|
|
|
|
expect(client_call.metadata).to eq(expected) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
it 'get a status from server when nothing else sent from server' do |
|
|
|
|
client_call = make_test_call |
|
|
|
|
ActiveCall.client_invoke(client_call) |
|
|
|
|
|
|
|
|
|
recvd_rpc = @server.request_call |
|
|
|
|
recvd_call = recvd_rpc.call |
|
|
|
|
|
|
|
|
|
server_call = ActiveCall.new( |
|
|
|
|
recvd_call, |
|
|
|
|
@pass_through, |
|
|
|
|
@pass_through, |
|
|
|
|
deadline, |
|
|
|
|
started: false) |
|
|
|
|
|
|
|
|
|
server_call.send_status(OK, 'OK') |
|
|
|
|
|
|
|
|
|
# Check that we can receive initial metadata and a status |
|
|
|
|
client_call.run_batch( |
|
|
|
|
CallOps::RECV_INITIAL_METADATA => nil) |
|
|
|
|
batch_result = client_call.run_batch( |
|
|
|
|
CallOps::RECV_STATUS_ON_CLIENT => nil) |
|
|
|
|
|
|
|
|
|
expect(batch_result.status.code).to eq(OK) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
it 'get a nil msg before a status when an OK status is sent' do |
|
|
|
|
call = make_test_call |
|
|
|
|
ActiveCall.client_invoke(call) |
|
|
|
@ -329,6 +529,125 @@ describe GRPC::ActiveCall do |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
# Test sending of the initial metadata in #run_server_bidi |
|
|
|
|
# from the server handler both implicitly and explicitly, |
|
|
|
|
# when the server handler function has one argument and two arguments |
|
|
|
|
describe '#run_server_bidi sanity tests', run_server_bidi: true do |
|
|
|
|
it 'sends the initial metadata implicitly if not already sent' do |
|
|
|
|
requests = ['first message', 'second message'] |
|
|
|
|
server_to_client_metadata = { 'test_key' => 'test_val' } |
|
|
|
|
server_status = OK |
|
|
|
|
|
|
|
|
|
client_call = make_test_call |
|
|
|
|
client_call.run_batch(CallOps::SEND_INITIAL_METADATA => {}) |
|
|
|
|
|
|
|
|
|
recvd_rpc = @server.request_call |
|
|
|
|
recvd_call = recvd_rpc.call |
|
|
|
|
server_call = ActiveCall.new(recvd_call, |
|
|
|
|
@pass_through, |
|
|
|
|
@pass_through, |
|
|
|
|
deadline, |
|
|
|
|
metadata_received: true, |
|
|
|
|
started: false, |
|
|
|
|
metadata_to_send: server_to_client_metadata) |
|
|
|
|
|
|
|
|
|
# Server handler that doesn't have access to a "call" |
|
|
|
|
# It echoes the requests |
|
|
|
|
fake_gen_each_reply_with_no_call_param = proc do |msgs| |
|
|
|
|
msgs |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
server_thread = Thread.new do |
|
|
|
|
server_call.run_server_bidi( |
|
|
|
|
fake_gen_each_reply_with_no_call_param) |
|
|
|
|
server_call.send_status(server_status) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
# Send the requests and send a close so the server can send a status |
|
|
|
|
requests.each do |message| |
|
|
|
|
client_call.run_batch(CallOps::SEND_MESSAGE => message) |
|
|
|
|
end |
|
|
|
|
client_call.run_batch(CallOps::SEND_CLOSE_FROM_CLIENT => nil) |
|
|
|
|
|
|
|
|
|
server_thread.join |
|
|
|
|
|
|
|
|
|
# Expect that initial metadata was sent, |
|
|
|
|
# the requests were echoed, and a status was sent |
|
|
|
|
batch_result = client_call.run_batch( |
|
|
|
|
CallOps::RECV_INITIAL_METADATA => nil) |
|
|
|
|
expect(batch_result.metadata).to eq(server_to_client_metadata) |
|
|
|
|
|
|
|
|
|
requests.each do |message| |
|
|
|
|
batch_result = client_call.run_batch( |
|
|
|
|
CallOps::RECV_MESSAGE => nil) |
|
|
|
|
expect(batch_result.message).to eq(message) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
batch_result = client_call.run_batch( |
|
|
|
|
CallOps::RECV_STATUS_ON_CLIENT => nil) |
|
|
|
|
expect(batch_result.status.code).to eq(server_status) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
it 'sends the metadata when sent explicitly and not already sent' do |
|
|
|
|
requests = ['first message', 'second message'] |
|
|
|
|
server_to_client_metadata = { 'test_key' => 'test_val' } |
|
|
|
|
server_status = OK |
|
|
|
|
|
|
|
|
|
client_call = make_test_call |
|
|
|
|
client_call.run_batch(CallOps::SEND_INITIAL_METADATA => {}) |
|
|
|
|
|
|
|
|
|
recvd_rpc = @server.request_call |
|
|
|
|
recvd_call = recvd_rpc.call |
|
|
|
|
server_call = ActiveCall.new(recvd_call, |
|
|
|
|
@pass_through, |
|
|
|
|
@pass_through, |
|
|
|
|
deadline, |
|
|
|
|
metadata_received: true, |
|
|
|
|
started: false) |
|
|
|
|
|
|
|
|
|
# Fake server handler that has access to a "call" object and |
|
|
|
|
# uses it to explicitly update and sent the initial metadata |
|
|
|
|
fake_gen_each_reply_with_call_param = proc do |msgs, call_param| |
|
|
|
|
call_param.merge_metadata_to_send(server_to_client_metadata) |
|
|
|
|
call_param.send_initial_metadata |
|
|
|
|
msgs |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
server_thread = Thread.new do |
|
|
|
|
server_call.run_server_bidi( |
|
|
|
|
fake_gen_each_reply_with_call_param) |
|
|
|
|
server_call.send_status(server_status) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
# Send requests and a close from the client so the server |
|
|
|
|
# can send a status |
|
|
|
|
requests.each do |message| |
|
|
|
|
client_call.run_batch( |
|
|
|
|
CallOps::SEND_MESSAGE => message) |
|
|
|
|
end |
|
|
|
|
client_call.run_batch( |
|
|
|
|
CallOps::SEND_CLOSE_FROM_CLIENT => nil) |
|
|
|
|
|
|
|
|
|
server_thread.join |
|
|
|
|
|
|
|
|
|
# Verify that the correct metadata was sent, the requests |
|
|
|
|
# were echoed, and the correct status was sent |
|
|
|
|
batch_result = client_call.run_batch( |
|
|
|
|
CallOps::RECV_INITIAL_METADATA => nil) |
|
|
|
|
expect(batch_result.metadata).to eq(server_to_client_metadata) |
|
|
|
|
|
|
|
|
|
requests.each do |message| |
|
|
|
|
batch_result = client_call.run_batch( |
|
|
|
|
CallOps::RECV_MESSAGE => nil) |
|
|
|
|
expect(batch_result.message).to eq(message) |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
batch_result = client_call.run_batch( |
|
|
|
|
CallOps::RECV_STATUS_ON_CLIENT => nil) |
|
|
|
|
expect(batch_result.status.code).to eq(server_status) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
def expect_server_to_receive(sent_text, **kw) |
|
|
|
|
c = expect_server_to_be_invoked(**kw) |
|
|
|
|
expect(c.remote_read).to eq(sent_text) |
|
|
|
|