grpc 1.4.1 → 1.4.5
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of grpc might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Makefile +2 -2
- data/src/ruby/ext/grpc/rb_call.c +23 -10
- data/src/ruby/ext/grpc/rb_call.h +3 -0
- data/src/ruby/ext/grpc/rb_call_credentials.c +6 -1
- data/src/ruby/ext/grpc/rb_channel_credentials.c +6 -0
- data/src/ruby/lib/grpc/generic/active_call.rb +137 -33
- data/src/ruby/lib/grpc/generic/bidi_call.rb +28 -34
- data/src/ruby/lib/grpc/generic/rpc_desc.rb +2 -2
- data/src/ruby/lib/grpc/generic/rpc_server.rb +1 -0
- data/src/ruby/lib/grpc/version.rb +1 -1
- data/src/ruby/spec/client_auth_spec.rb +152 -0
- data/src/ruby/spec/client_server_spec.rb +29 -5
- data/src/ruby/spec/generic/active_call_spec.rb +2 -2
- data/src/ruby/spec/generic/client_stub_spec.rb +313 -70
- data/src/ruby/spec/generic/rpc_desc_spec.rb +5 -5
- data/src/ruby/spec/generic/rpc_server_spec.rb +145 -0
- data/src/ruby/spec/testdata/client.key +16 -0
- data/src/ruby/spec/testdata/client.pem +14 -0
- metadata +8 -2
@@ -77,12 +77,19 @@ module GRPC
|
|
77
77
|
# block that can be invoked with each response.
|
78
78
|
#
|
79
79
|
# @param requests the Enumerable of requests to send
|
80
|
-
# @param
|
80
|
+
# @param set_input_stream_done [Proc] called back when we're done
|
81
|
+
# reading the input stream
|
82
|
+
# @param set_input_stream_done [Proc] called back when we're done
|
83
|
+
# sending data on the output stream
|
81
84
|
# @return an Enumerator of requests to yield
|
82
|
-
def run_on_client(requests,
|
83
|
-
|
84
|
-
|
85
|
-
|
85
|
+
def run_on_client(requests,
|
86
|
+
set_input_stream_done,
|
87
|
+
set_output_stream_done,
|
88
|
+
&blk)
|
89
|
+
@enq_th = Thread.new do
|
90
|
+
write_loop(requests, set_output_stream_done: set_output_stream_done)
|
91
|
+
end
|
92
|
+
read_loop(set_input_stream_done, &blk)
|
86
93
|
end
|
87
94
|
|
88
95
|
# Begins orchestration of the Bidi stream for a server generating replies.
|
@@ -96,12 +103,17 @@ module GRPC
|
|
96
103
|
# produced by gen_each_reply could ignore the received_msgs
|
97
104
|
#
|
98
105
|
# @param gen_each_reply [Proc] generates the BiDi stream replies.
|
99
|
-
|
106
|
+
# @param set_input_steam_done [Proc] call back to call when
|
107
|
+
# the reads have been completely read through.
|
108
|
+
def run_on_server(gen_each_reply, set_input_stream_done)
|
100
109
|
# Pass in the optional call object parameter if possible
|
101
110
|
if gen_each_reply.arity == 1
|
102
|
-
replys = gen_each_reply.call(
|
111
|
+
replys = gen_each_reply.call(
|
112
|
+
read_loop(set_input_stream_done, is_client: false))
|
103
113
|
elsif gen_each_reply.arity == 2
|
104
|
-
replys = gen_each_reply.call(
|
114
|
+
replys = gen_each_reply.call(
|
115
|
+
read_loop(set_input_stream_done, is_client: false),
|
116
|
+
@req_view)
|
105
117
|
else
|
106
118
|
fail 'Illegal arity of reply generator'
|
107
119
|
end
|
@@ -114,22 +126,6 @@ module GRPC
|
|
114
126
|
END_OF_READS = :end_of_reads
|
115
127
|
END_OF_WRITES = :end_of_writes
|
116
128
|
|
117
|
-
# signals that bidi operation is complete
|
118
|
-
def notify_done
|
119
|
-
return unless @op_notifier
|
120
|
-
GRPC.logger.debug("bidi-notify-done: notifying #{@op_notifier}")
|
121
|
-
@op_notifier.notify(self)
|
122
|
-
end
|
123
|
-
|
124
|
-
# signals that a bidi operation is complete (read + write)
|
125
|
-
def finished
|
126
|
-
@done_mutex.synchronize do
|
127
|
-
return unless @reads_complete && @writes_complete && !@complete
|
128
|
-
@call.close
|
129
|
-
@complete = true
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
129
|
# performs a read using @call.run_batch, ensures metadata is set up
|
134
130
|
def read_using_run_batch
|
135
131
|
ops = { RECV_MESSAGE => nil }
|
@@ -142,7 +138,8 @@ module GRPC
|
|
142
138
|
batch_result
|
143
139
|
end
|
144
140
|
|
145
|
-
|
141
|
+
# set_output_stream_done is relevant on client-side
|
142
|
+
def write_loop(requests, is_client: true, set_output_stream_done: nil)
|
146
143
|
GRPC.logger.debug('bidi-write-loop: starting')
|
147
144
|
count = 0
|
148
145
|
requests.each do |req|
|
@@ -166,23 +163,20 @@ module GRPC
|
|
166
163
|
GRPC.logger.debug("bidi-write-loop: client sent #{count}, waiting")
|
167
164
|
@call.run_batch(SEND_CLOSE_FROM_CLIENT => nil)
|
168
165
|
GRPC.logger.debug('bidi-write-loop: done')
|
169
|
-
notify_done
|
170
|
-
@writes_complete = true
|
171
|
-
finished
|
172
166
|
end
|
173
167
|
GRPC.logger.debug('bidi-write-loop: finished')
|
174
168
|
rescue StandardError => e
|
175
169
|
GRPC.logger.warn('bidi-write-loop: failed')
|
176
170
|
GRPC.logger.warn(e)
|
177
|
-
notify_done
|
178
|
-
@writes_complete = true
|
179
|
-
finished
|
180
171
|
raise e
|
172
|
+
ensure
|
173
|
+
set_output_stream_done.call if is_client
|
181
174
|
end
|
182
175
|
|
183
176
|
# Provides an enumerator that yields results of remote reads
|
184
|
-
def read_loop(is_client: true)
|
177
|
+
def read_loop(set_input_stream_done, is_client: true)
|
185
178
|
return enum_for(:read_loop,
|
179
|
+
set_input_stream_done,
|
186
180
|
is_client: is_client) unless block_given?
|
187
181
|
GRPC.logger.debug('bidi-read-loop: starting')
|
188
182
|
begin
|
@@ -216,10 +210,10 @@ module GRPC
|
|
216
210
|
GRPC.logger.warn('bidi: read-loop failed')
|
217
211
|
GRPC.logger.warn(e)
|
218
212
|
raise e
|
213
|
+
ensure
|
214
|
+
set_input_stream_done.call
|
219
215
|
end
|
220
216
|
GRPC.logger.debug('bidi-read-loop: finished')
|
221
|
-
@reads_complete = true
|
222
|
-
finished
|
223
217
|
# Make sure that the write loop is done done before finishing the call.
|
224
218
|
# Note that blocking is ok at this point because we've already received
|
225
219
|
# a status
|
@@ -63,7 +63,7 @@ module GRPC
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def handle_request_response(active_call, mth)
|
66
|
-
req = active_call.
|
66
|
+
req = active_call.read_unary_request
|
67
67
|
resp = mth.call(req, active_call.single_req_view)
|
68
68
|
active_call.server_unary_response(
|
69
69
|
resp, trailing_metadata: active_call.output_metadata)
|
@@ -76,7 +76,7 @@ module GRPC
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def handle_server_streamer(active_call, mth)
|
79
|
-
req = active_call.
|
79
|
+
req = active_call.read_unary_request
|
80
80
|
replys = mth.call(req, active_call.single_req_view)
|
81
81
|
replys.each { |r| active_call.remote_send(r) }
|
82
82
|
send_status(active_call, OK, 'OK', active_call.output_metadata)
|
@@ -0,0 +1,152 @@
|
|
1
|
+
# Copyright 2015, Google Inc.
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are
|
6
|
+
# met:
|
7
|
+
#
|
8
|
+
# * Redistributions of source code must retain the above copyright
|
9
|
+
# notice, this list of conditions and the following disclaimer.
|
10
|
+
# * Redistributions in binary form must reproduce the above
|
11
|
+
# copyright notice, this list of conditions and the following disclaimer
|
12
|
+
# in the documentation and/or other materials provided with the
|
13
|
+
# distribution.
|
14
|
+
# * Neither the name of Google Inc. nor the names of its
|
15
|
+
# contributors may be used to endorse or promote products derived from
|
16
|
+
# this software without specific prior written permission.
|
17
|
+
#
|
18
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
19
|
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
20
|
+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
21
|
+
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
22
|
+
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
23
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
24
|
+
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
26
|
+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
27
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
|
30
|
+
require 'grpc'
|
31
|
+
|
32
|
+
def create_channel_creds
|
33
|
+
test_root = File.join(File.dirname(__FILE__), 'testdata')
|
34
|
+
files = ['ca.pem', 'client.key', 'client.pem']
|
35
|
+
creds = files.map { |f| File.open(File.join(test_root, f)).read }
|
36
|
+
GRPC::Core::ChannelCredentials.new(creds[0], creds[1], creds[2])
|
37
|
+
end
|
38
|
+
|
39
|
+
def client_cert
|
40
|
+
test_root = File.join(File.dirname(__FILE__), 'testdata')
|
41
|
+
cert = File.open(File.join(test_root, 'client.pem')).read
|
42
|
+
fail unless cert.is_a?(String)
|
43
|
+
cert
|
44
|
+
end
|
45
|
+
|
46
|
+
def create_server_creds
|
47
|
+
test_root = File.join(File.dirname(__FILE__), 'testdata')
|
48
|
+
p "test root: #{test_root}"
|
49
|
+
files = ['ca.pem', 'server1.key', 'server1.pem']
|
50
|
+
creds = files.map { |f| File.open(File.join(test_root, f)).read }
|
51
|
+
GRPC::Core::ServerCredentials.new(
|
52
|
+
creds[0],
|
53
|
+
[{ private_key: creds[1], cert_chain: creds[2] }],
|
54
|
+
true) # force client auth
|
55
|
+
end
|
56
|
+
|
57
|
+
# A test message
|
58
|
+
class EchoMsg
|
59
|
+
def self.marshal(_o)
|
60
|
+
''
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.unmarshal(_o)
|
64
|
+
EchoMsg.new
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# a test service that checks the cert of its peer
|
69
|
+
class SslTestService
|
70
|
+
include GRPC::GenericService
|
71
|
+
rpc :an_rpc, EchoMsg, EchoMsg
|
72
|
+
rpc :a_client_streaming_rpc, stream(EchoMsg), EchoMsg
|
73
|
+
rpc :a_server_streaming_rpc, EchoMsg, stream(EchoMsg)
|
74
|
+
rpc :a_bidi_rpc, stream(EchoMsg), stream(EchoMsg)
|
75
|
+
|
76
|
+
def check_peer_cert(call)
|
77
|
+
error_msg = "want:\n#{client_cert}\n\ngot:\n#{call.peer_cert}"
|
78
|
+
fail(error_msg) unless call.peer_cert == client_cert
|
79
|
+
end
|
80
|
+
|
81
|
+
def an_rpc(req, call)
|
82
|
+
check_peer_cert(call)
|
83
|
+
req
|
84
|
+
end
|
85
|
+
|
86
|
+
def a_client_streaming_rpc(call)
|
87
|
+
check_peer_cert(call)
|
88
|
+
call.each_remote_read.each { |r| p r }
|
89
|
+
EchoMsg.new
|
90
|
+
end
|
91
|
+
|
92
|
+
def a_server_streaming_rpc(_, call)
|
93
|
+
check_peer_cert(call)
|
94
|
+
[EchoMsg.new, EchoMsg.new]
|
95
|
+
end
|
96
|
+
|
97
|
+
def a_bidi_rpc(requests, call)
|
98
|
+
check_peer_cert(call)
|
99
|
+
requests.each { |r| p r }
|
100
|
+
[EchoMsg.new, EchoMsg.new]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
SslTestServiceStub = SslTestService.rpc_stub_class
|
105
|
+
|
106
|
+
describe 'client-server auth' do
|
107
|
+
RpcServer = GRPC::RpcServer
|
108
|
+
|
109
|
+
before(:all) do
|
110
|
+
server_opts = {
|
111
|
+
poll_period: 1
|
112
|
+
}
|
113
|
+
@srv = RpcServer.new(**server_opts)
|
114
|
+
port = @srv.add_http2_port('0.0.0.0:0', create_server_creds)
|
115
|
+
@srv.handle(SslTestService)
|
116
|
+
@srv_thd = Thread.new { @srv.run }
|
117
|
+
@srv.wait_till_running
|
118
|
+
|
119
|
+
client_opts = {
|
120
|
+
channel_args: {
|
121
|
+
GRPC::Core::Channel::SSL_TARGET => 'foo.test.google.fr'
|
122
|
+
}
|
123
|
+
}
|
124
|
+
@stub = SslTestServiceStub.new("localhost:#{port}",
|
125
|
+
create_channel_creds,
|
126
|
+
**client_opts)
|
127
|
+
end
|
128
|
+
|
129
|
+
after(:all) do
|
130
|
+
expect(@srv.stopped?).to be(false)
|
131
|
+
@srv.stop
|
132
|
+
@srv_thd.join
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'client-server auth with unary RPCs' do
|
136
|
+
@stub.an_rpc(EchoMsg.new)
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'client-server auth with client streaming RPCs' do
|
140
|
+
@stub.a_client_streaming_rpc([EchoMsg.new, EchoMsg.new])
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'client-server auth with server streaming RPCs' do
|
144
|
+
responses = @stub.a_server_streaming_rpc(EchoMsg.new)
|
145
|
+
responses.each { |r| p r }
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'client-server auth with bidi RPCs' do
|
149
|
+
responses = @stub.a_bidi_rpc([EchoMsg.new, EchoMsg.new])
|
150
|
+
responses.each { |r| p r }
|
151
|
+
end
|
152
|
+
end
|
@@ -463,11 +463,18 @@ describe 'the secure http client/server' do
|
|
463
463
|
it_behaves_like 'GRPC metadata delivery works OK' do
|
464
464
|
end
|
465
465
|
|
466
|
-
|
467
|
-
auth_proc = proc {
|
466
|
+
def credentials_update_test(creds_update_md)
|
467
|
+
auth_proc = proc { creds_update_md }
|
468
468
|
call_creds = GRPC::Core::CallCredentials.new(auth_proc)
|
469
|
-
|
470
|
-
|
469
|
+
|
470
|
+
initial_md_key = 'k2'
|
471
|
+
initial_md_val = 'v2'
|
472
|
+
initial_md = {}
|
473
|
+
initial_md[initial_md_key] = initial_md_val
|
474
|
+
expected_md = creds_update_md.clone
|
475
|
+
fail 'bad test param' unless expected_md[initial_md_key].nil?
|
476
|
+
expected_md[initial_md_key] = initial_md_val
|
477
|
+
|
471
478
|
recvd_rpc = nil
|
472
479
|
rcv_thread = Thread.new do
|
473
480
|
recvd_rpc = @server.request_call
|
@@ -476,7 +483,7 @@ describe 'the secure http client/server' do
|
|
476
483
|
call = new_client_call
|
477
484
|
call.set_credentials! call_creds
|
478
485
|
client_ops = {
|
479
|
-
CallOps::SEND_INITIAL_METADATA =>
|
486
|
+
CallOps::SEND_INITIAL_METADATA => initial_md
|
480
487
|
}
|
481
488
|
batch_result = call.run_batch(client_ops)
|
482
489
|
expect(batch_result.send_metadata).to be true
|
@@ -488,4 +495,21 @@ describe 'the secure http client/server' do
|
|
488
495
|
replace_symbols = Hash[expected_md.each_pair.collect { |x, y| [x.to_s, y] }]
|
489
496
|
expect(recvd_md).to eq(recvd_md.merge(replace_symbols))
|
490
497
|
end
|
498
|
+
|
499
|
+
it 'modifies metadata with CallCredentials' do
|
500
|
+
credentials_update_test('k1' => 'updated-v1')
|
501
|
+
end
|
502
|
+
|
503
|
+
it 'modifies large metadata with CallCredentials' do
|
504
|
+
val_array = %w(
|
505
|
+
'00000000000000000000000000000000000000000000000000000000000000',
|
506
|
+
'11111111111111111111111111111111111111111111111111111111111111',
|
507
|
+
)
|
508
|
+
md = {
|
509
|
+
k3: val_array,
|
510
|
+
k4: '0000000000000000000000000000000000000000000000000000000000',
|
511
|
+
keeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeey5: 'v1'
|
512
|
+
}
|
513
|
+
credentials_update_test(md)
|
514
|
+
end
|
491
515
|
end
|
@@ -488,7 +488,7 @@ describe GRPC::ActiveCall do
|
|
488
488
|
server_call.remote_send('server_response')
|
489
489
|
expect(client_call.remote_read).to eq('server_response')
|
490
490
|
server_call.send_status(OK, 'status code is OK')
|
491
|
-
expect { client_call.
|
491
|
+
expect { client_call.receive_and_check_status }.to_not raise_error
|
492
492
|
end
|
493
493
|
|
494
494
|
it 'finishes ok if the server sends an early status response' do
|
@@ -505,7 +505,7 @@ describe GRPC::ActiveCall do
|
|
505
505
|
expect do
|
506
506
|
call.run_batch(CallOps::SEND_CLOSE_FROM_CLIENT => nil)
|
507
507
|
end.to_not raise_error
|
508
|
-
expect { client_call.
|
508
|
+
expect { client_call.receive_and_check_status }.to_not raise_error
|
509
509
|
end
|
510
510
|
|
511
511
|
it 'finishes ok if SEND_CLOSE and RECV_STATUS has been sent' do
|
@@ -51,6 +51,53 @@ include GRPC::Core::StatusCodes
|
|
51
51
|
include GRPC::Core::TimeConsts
|
52
52
|
include GRPC::Core::CallOps
|
53
53
|
|
54
|
+
# check that methods on a finished/closed call t crash
|
55
|
+
def check_op_view_of_finished_client_call(op_view,
|
56
|
+
expected_metadata,
|
57
|
+
expected_trailing_metadata)
|
58
|
+
# use read_response_stream to try to iterate through
|
59
|
+
# possible response stream
|
60
|
+
fail('need something to attempt reads') unless block_given?
|
61
|
+
expect do
|
62
|
+
resp = op_view.execute
|
63
|
+
yield resp
|
64
|
+
end.to raise_error(GRPC::Core::CallError)
|
65
|
+
|
66
|
+
expect { op_view.start_call }.to raise_error(RuntimeError)
|
67
|
+
|
68
|
+
sanity_check_values_of_accessors(op_view,
|
69
|
+
expected_metadata,
|
70
|
+
expected_trailing_metadata)
|
71
|
+
|
72
|
+
expect do
|
73
|
+
op_view.wait
|
74
|
+
op_view.cancel
|
75
|
+
op_view.write_flag = 1
|
76
|
+
end.to_not raise_error
|
77
|
+
end
|
78
|
+
|
79
|
+
def sanity_check_values_of_accessors(op_view,
|
80
|
+
expected_metadata,
|
81
|
+
expected_trailing_metadata)
|
82
|
+
expected_status = Struct::Status.new
|
83
|
+
expected_status.code = 0
|
84
|
+
expected_status.details = 'OK'
|
85
|
+
expected_status.metadata = expected_trailing_metadata
|
86
|
+
|
87
|
+
expect(op_view.status).to eq(expected_status)
|
88
|
+
expect(op_view.metadata).to eq(expected_metadata)
|
89
|
+
expect(op_view.trailing_metadata).to eq(expected_trailing_metadata)
|
90
|
+
|
91
|
+
expect(op_view.cancelled?).to be(false)
|
92
|
+
expect(op_view.write_flag).to be(nil)
|
93
|
+
|
94
|
+
# The deadline attribute of a call can be either
|
95
|
+
# a GRPC::Core::TimeSpec or a Time, which are mutually exclusive.
|
96
|
+
# TODO: fix so that the accessor always returns the same type.
|
97
|
+
expect(op_view.deadline.is_a?(GRPC::Core::TimeSpec) ||
|
98
|
+
op_view.deadline.is_a?(Time)).to be(true)
|
99
|
+
end
|
100
|
+
|
54
101
|
describe 'ClientStub' do
|
55
102
|
let(:noop) { proc { |x| x } }
|
56
103
|
|
@@ -60,6 +107,7 @@ describe 'ClientStub' do
|
|
60
107
|
@method = 'an_rpc_method'
|
61
108
|
@pass = OK
|
62
109
|
@fail = INTERNAL
|
110
|
+
@metadata = { k1: 'v1', k2: 'v2' }
|
63
111
|
end
|
64
112
|
|
65
113
|
after(:each) do
|
@@ -122,7 +170,7 @@ describe 'ClientStub' do
|
|
122
170
|
end
|
123
171
|
end
|
124
172
|
|
125
|
-
describe '#request_response' do
|
173
|
+
describe '#request_response', request_response: true do
|
126
174
|
before(:each) do
|
127
175
|
@sent_msg, @resp = 'a_msg', 'a_reply'
|
128
176
|
end
|
@@ -137,16 +185,42 @@ describe 'ClientStub' do
|
|
137
185
|
th.join
|
138
186
|
end
|
139
187
|
|
140
|
-
|
188
|
+
def metadata_test(md)
|
141
189
|
server_port = create_test_server
|
142
190
|
host = "localhost:#{server_port}"
|
143
191
|
th = run_request_response(@sent_msg, @resp, @pass,
|
144
|
-
|
192
|
+
expected_metadata: md)
|
145
193
|
stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
|
194
|
+
@metadata = md
|
146
195
|
expect(get_response(stub)).to eq(@resp)
|
147
196
|
th.join
|
148
197
|
end
|
149
198
|
|
199
|
+
it 'should send metadata to the server ok' do
|
200
|
+
metadata_test(k1: 'v1', k2: 'v2')
|
201
|
+
end
|
202
|
+
|
203
|
+
# these tests mostly try to exercise when md might be allocated
|
204
|
+
# instead of inlined
|
205
|
+
it 'should send metadata with multiple large md to the server ok' do
|
206
|
+
val_array = %w(
|
207
|
+
'00000000000000000000000000000000000000000000000000000000000000',
|
208
|
+
'11111111111111111111111111111111111111111111111111111111111111',
|
209
|
+
'22222222222222222222222222222222222222222222222222222222222222',
|
210
|
+
)
|
211
|
+
md = {
|
212
|
+
k1: val_array,
|
213
|
+
k2: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
214
|
+
k3: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
|
215
|
+
k4: 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccc',
|
216
|
+
keeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeey5: 'v5',
|
217
|
+
'k66666666666666666666666666666666666666666666666666666' => 'v6',
|
218
|
+
'k77777777777777777777777777777777777777777777777777777' => 'v7',
|
219
|
+
'k88888888888888888888888888888888888888888888888888888' => 'v8'
|
220
|
+
}
|
221
|
+
metadata_test(md)
|
222
|
+
end
|
223
|
+
|
150
224
|
it 'should send a request when configured using an override channel' do
|
151
225
|
server_port = create_test_server
|
152
226
|
alt_host = "localhost:#{server_port}"
|
@@ -202,13 +276,24 @@ describe 'ClientStub' do
|
|
202
276
|
# Kill the server thread so tests can complete
|
203
277
|
th.kill
|
204
278
|
end
|
279
|
+
|
280
|
+
it 'should raise ArgumentError if metadata contains invalid values' do
|
281
|
+
@metadata.merge!(k3: 3)
|
282
|
+
server_port = create_test_server
|
283
|
+
host = "localhost:#{server_port}"
|
284
|
+
stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
|
285
|
+
expect do
|
286
|
+
get_response(stub)
|
287
|
+
end.to raise_error(ArgumentError,
|
288
|
+
/Header values must be of type string or array/)
|
289
|
+
end
|
205
290
|
end
|
206
291
|
|
207
292
|
describe 'without a call operation' do
|
208
293
|
def get_response(stub, credentials: nil)
|
209
294
|
puts credentials.inspect
|
210
295
|
stub.request_response(@method, @sent_msg, noop, noop,
|
211
|
-
metadata:
|
296
|
+
metadata: @metadata,
|
212
297
|
credentials: credentials)
|
213
298
|
end
|
214
299
|
|
@@ -216,40 +301,62 @@ describe 'ClientStub' do
|
|
216
301
|
end
|
217
302
|
|
218
303
|
describe 'via a call operation' do
|
304
|
+
after(:each) do
|
305
|
+
# make sure op.wait doesn't hang, even if there's a bad status
|
306
|
+
@op.wait
|
307
|
+
end
|
219
308
|
def get_response(stub, run_start_call_first: false, credentials: nil)
|
220
|
-
op = stub.request_response(@method, @sent_msg, noop, noop,
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
expect(op).to be_a(GRPC::ActiveCall::Operation)
|
226
|
-
op.start_call if run_start_call_first
|
227
|
-
result = op.execute
|
228
|
-
op.wait # make sure wait doesn't hang
|
309
|
+
@op = stub.request_response(@method, @sent_msg, noop, noop,
|
310
|
+
return_op: true,
|
311
|
+
metadata: @metadata,
|
312
|
+
deadline: from_relative_time(2),
|
313
|
+
credentials: credentials)
|
314
|
+
expect(@op).to be_a(GRPC::ActiveCall::Operation)
|
315
|
+
@op.start_call if run_start_call_first
|
316
|
+
result = @op.execute
|
229
317
|
result
|
230
318
|
end
|
231
319
|
|
232
320
|
it_behaves_like 'request response'
|
233
321
|
|
234
|
-
|
322
|
+
def run_op_view_metadata_test(run_start_call_first)
|
235
323
|
server_port = create_test_server
|
236
324
|
host = "localhost:#{server_port}"
|
237
|
-
|
238
|
-
|
325
|
+
|
326
|
+
@server_initial_md = { 'sk1' => 'sv1', 'sk2' => 'sv2' }
|
327
|
+
@server_trailing_md = { 'tk1' => 'tv1', 'tk2' => 'tv2' }
|
328
|
+
th = run_request_response(
|
329
|
+
@sent_msg, @resp, @pass,
|
330
|
+
expected_metadata: @metadata,
|
331
|
+
server_initial_md: @server_initial_md,
|
332
|
+
server_trailing_md: @server_trailing_md)
|
239
333
|
stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
|
240
|
-
expect(
|
334
|
+
expect(
|
335
|
+
get_response(stub,
|
336
|
+
run_start_call_first: run_start_call_first)).to eq(@resp)
|
241
337
|
th.join
|
242
338
|
end
|
339
|
+
|
340
|
+
it 'sends metadata to the server ok when running start_call first' do
|
341
|
+
run_op_view_metadata_test(true)
|
342
|
+
check_op_view_of_finished_client_call(
|
343
|
+
@op, @server_initial_md, @server_trailing_md) { |r| p r }
|
344
|
+
end
|
345
|
+
|
346
|
+
it 'does not crash when used after the call has been finished' do
|
347
|
+
run_op_view_metadata_test(false)
|
348
|
+
check_op_view_of_finished_client_call(
|
349
|
+
@op, @server_initial_md, @server_trailing_md) { |r| p r }
|
350
|
+
end
|
243
351
|
end
|
244
352
|
end
|
245
353
|
|
246
|
-
describe '#client_streamer' do
|
354
|
+
describe '#client_streamer', client_streamer: true do
|
247
355
|
before(:each) do
|
248
356
|
Thread.abort_on_exception = true
|
249
357
|
server_port = create_test_server
|
250
358
|
host = "localhost:#{server_port}"
|
251
359
|
@stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
|
252
|
-
@metadata = { k1: 'v1', k2: 'v2' }
|
253
360
|
@sent_msgs = Array.new(3) { |i| 'msg_' + (i + 1).to_s }
|
254
361
|
@resp = 'a_reply'
|
255
362
|
end
|
@@ -262,7 +369,8 @@ describe 'ClientStub' do
|
|
262
369
|
end
|
263
370
|
|
264
371
|
it 'should send metadata to the server ok' do
|
265
|
-
th = run_client_streamer(@sent_msgs, @resp, @pass,
|
372
|
+
th = run_client_streamer(@sent_msgs, @resp, @pass,
|
373
|
+
expected_metadata: @metadata)
|
266
374
|
expect(get_response(@stub)).to eq(@resp)
|
267
375
|
th.join
|
268
376
|
end
|
@@ -293,27 +401,50 @@ describe 'ClientStub' do
|
|
293
401
|
end
|
294
402
|
|
295
403
|
describe 'via a call operation' do
|
404
|
+
after(:each) do
|
405
|
+
# make sure op.wait doesn't hang, even if there's a bad status
|
406
|
+
@op.wait
|
407
|
+
end
|
296
408
|
def get_response(stub, run_start_call_first: false)
|
297
|
-
op = stub.client_streamer(@method, @sent_msgs, noop, noop,
|
298
|
-
|
299
|
-
expect(op).to be_a(GRPC::ActiveCall::Operation)
|
300
|
-
op.start_call if run_start_call_first
|
301
|
-
result = op.execute
|
302
|
-
op.wait # make sure wait doesn't hang
|
409
|
+
@op = stub.client_streamer(@method, @sent_msgs, noop, noop,
|
410
|
+
return_op: true, metadata: @metadata)
|
411
|
+
expect(@op).to be_a(GRPC::ActiveCall::Operation)
|
412
|
+
@op.start_call if run_start_call_first
|
413
|
+
result = @op.execute
|
303
414
|
result
|
304
415
|
end
|
305
416
|
|
306
417
|
it_behaves_like 'client streaming'
|
307
418
|
|
308
|
-
|
309
|
-
|
310
|
-
|
419
|
+
def run_op_view_metadata_test(run_start_call_first)
|
420
|
+
@server_initial_md = { 'sk1' => 'sv1', 'sk2' => 'sv2' }
|
421
|
+
@server_trailing_md = { 'tk1' => 'tv1', 'tk2' => 'tv2' }
|
422
|
+
th = run_client_streamer(
|
423
|
+
@sent_msgs, @resp, @pass,
|
424
|
+
expected_metadata: @metadata,
|
425
|
+
server_initial_md: @server_initial_md,
|
426
|
+
server_trailing_md: @server_trailing_md)
|
427
|
+
expect(
|
428
|
+
get_response(@stub,
|
429
|
+
run_start_call_first: run_start_call_first)).to eq(@resp)
|
311
430
|
th.join
|
312
431
|
end
|
432
|
+
|
433
|
+
it 'sends metadata to the server ok when running start_call first' do
|
434
|
+
run_op_view_metadata_test(true)
|
435
|
+
check_op_view_of_finished_client_call(
|
436
|
+
@op, @server_initial_md, @server_trailing_md) { |r| p r }
|
437
|
+
end
|
438
|
+
|
439
|
+
it 'does not crash when used after the call has been finished' do
|
440
|
+
run_op_view_metadata_test(false)
|
441
|
+
check_op_view_of_finished_client_call(
|
442
|
+
@op, @server_initial_md, @server_trailing_md) { |r| p r }
|
443
|
+
end
|
313
444
|
end
|
314
445
|
end
|
315
446
|
|
316
|
-
describe '#server_streamer' do
|
447
|
+
describe '#server_streamer', server_streamer: true do
|
317
448
|
before(:each) do
|
318
449
|
@sent_msg = 'a_msg'
|
319
450
|
@replys = Array.new(3) { |i| 'reply_' + (i + 1).to_s }
|
@@ -343,18 +474,42 @@ describe 'ClientStub' do
|
|
343
474
|
server_port = create_test_server
|
344
475
|
host = "localhost:#{server_port}"
|
345
476
|
th = run_server_streamer(@sent_msg, @replys, @fail,
|
346
|
-
k1: 'v1', k2: 'v2')
|
477
|
+
expected_metadata: { k1: 'v1', k2: 'v2' })
|
347
478
|
stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
|
348
479
|
e = get_responses(stub)
|
349
480
|
expect { e.collect { |r| r } }.to raise_error(GRPC::BadStatus)
|
350
481
|
th.join
|
351
482
|
end
|
483
|
+
|
484
|
+
it 'should raise ArgumentError if metadata contains invalid values' do
|
485
|
+
@metadata.merge!(k3: 3)
|
486
|
+
server_port = create_test_server
|
487
|
+
host = "localhost:#{server_port}"
|
488
|
+
stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
|
489
|
+
expect do
|
490
|
+
get_responses(stub)
|
491
|
+
end.to raise_error(ArgumentError,
|
492
|
+
/Header values must be of type string or array/)
|
493
|
+
end
|
494
|
+
|
495
|
+
it 'the call terminates when there is an unmarshalling error' do
|
496
|
+
server_port = create_test_server
|
497
|
+
host = "localhost:#{server_port}"
|
498
|
+
th = run_server_streamer(@sent_msg, @replys, @pass)
|
499
|
+
stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
|
500
|
+
|
501
|
+
unmarshal = proc { fail(ArgumentError, 'test unmarshalling error') }
|
502
|
+
expect do
|
503
|
+
get_responses(stub, unmarshal: unmarshal).collect { |r| r }
|
504
|
+
end.to raise_error(ArgumentError, 'test unmarshalling error')
|
505
|
+
th.join
|
506
|
+
end
|
352
507
|
end
|
353
508
|
|
354
509
|
describe 'without a call operation' do
|
355
|
-
def get_responses(stub)
|
356
|
-
e = stub.server_streamer(@method, @sent_msg, noop,
|
357
|
-
metadata:
|
510
|
+
def get_responses(stub, unmarshal: noop)
|
511
|
+
e = stub.server_streamer(@method, @sent_msg, noop, unmarshal,
|
512
|
+
metadata: @metadata)
|
358
513
|
expect(e).to be_a(Enumerator)
|
359
514
|
e
|
360
515
|
end
|
@@ -366,10 +521,10 @@ describe 'ClientStub' do
|
|
366
521
|
after(:each) do
|
367
522
|
@op.wait # make sure wait doesn't hang
|
368
523
|
end
|
369
|
-
def get_responses(stub, run_start_call_first: false)
|
370
|
-
@op = stub.server_streamer(@method, @sent_msg, noop,
|
524
|
+
def get_responses(stub, run_start_call_first: false, unmarshal: noop)
|
525
|
+
@op = stub.server_streamer(@method, @sent_msg, noop, unmarshal,
|
371
526
|
return_op: true,
|
372
|
-
metadata:
|
527
|
+
metadata: @metadata)
|
373
528
|
expect(@op).to be_a(GRPC::ActiveCall::Operation)
|
374
529
|
@op.start_call if run_start_call_first
|
375
530
|
e = @op.execute
|
@@ -379,20 +534,41 @@ describe 'ClientStub' do
|
|
379
534
|
|
380
535
|
it_behaves_like 'server streaming'
|
381
536
|
|
382
|
-
|
537
|
+
def run_op_view_metadata_test(run_start_call_first)
|
383
538
|
server_port = create_test_server
|
384
539
|
host = "localhost:#{server_port}"
|
385
|
-
|
386
|
-
|
540
|
+
@server_initial_md = { 'sk1' => 'sv1', 'sk2' => 'sv2' }
|
541
|
+
@server_trailing_md = { 'tk1' => 'tv1', 'tk2' => 'tv2' }
|
542
|
+
th = run_server_streamer(
|
543
|
+
@sent_msg, @replys, @pass,
|
544
|
+
expected_metadata: @metadata,
|
545
|
+
server_initial_md: @server_initial_md,
|
546
|
+
server_trailing_md: @server_trailing_md)
|
387
547
|
stub = GRPC::ClientStub.new(host, :this_channel_is_insecure)
|
388
|
-
e = get_responses(stub, run_start_call_first:
|
389
|
-
expect
|
548
|
+
e = get_responses(stub, run_start_call_first: run_start_call_first)
|
549
|
+
expect(e.collect { |r| r }).to eq(@replys)
|
390
550
|
th.join
|
391
551
|
end
|
552
|
+
|
553
|
+
it 'should send metadata to the server ok when start_call is run first' do
|
554
|
+
run_op_view_metadata_test(true)
|
555
|
+
check_op_view_of_finished_client_call(
|
556
|
+
@op, @server_initial_md, @server_trailing_md) do |responses|
|
557
|
+
responses.each { |r| p r }
|
558
|
+
end
|
559
|
+
end
|
560
|
+
|
561
|
+
it 'does not crash when used after the call has been finished' do
|
562
|
+
run_op_view_metadata_test(false)
|
563
|
+
check_op_view_of_finished_client_call(
|
564
|
+
@op, @server_initial_md, @server_trailing_md) do |responses|
|
565
|
+
responses.each { |r| p r }
|
566
|
+
end
|
567
|
+
end
|
392
568
|
end
|
393
569
|
end
|
394
570
|
|
395
|
-
describe '#bidi_streamer' do
|
571
|
+
describe '#bidi_streamer', bidi: true do
|
396
572
|
before(:each) do
|
397
573
|
@sent_msgs = Array.new(3) { |i| 'msg_' + (i + 1).to_s }
|
398
574
|
@replys = Array.new(3) { |i| 'reply_' + (i + 1).to_s }
|
@@ -401,7 +577,7 @@ describe 'ClientStub' do
|
|
401
577
|
end
|
402
578
|
|
403
579
|
shared_examples 'bidi streaming' do
|
404
|
-
it 'supports sending all the requests first'
|
580
|
+
it 'supports sending all the requests first' do
|
405
581
|
th = run_bidi_streamer_handle_inputs_first(@sent_msgs, @replys,
|
406
582
|
@pass)
|
407
583
|
stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
|
@@ -410,7 +586,7 @@ describe 'ClientStub' do
|
|
410
586
|
th.join
|
411
587
|
end
|
412
588
|
|
413
|
-
it 'supports client-initiated ping pong'
|
589
|
+
it 'supports client-initiated ping pong' do
|
414
590
|
th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, true)
|
415
591
|
stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
|
416
592
|
e = get_responses(stub)
|
@@ -418,18 +594,39 @@ describe 'ClientStub' do
|
|
418
594
|
th.join
|
419
595
|
end
|
420
596
|
|
421
|
-
it 'supports a server-initiated ping pong'
|
597
|
+
it 'supports a server-initiated ping pong' do
|
422
598
|
th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, false)
|
423
599
|
stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
|
424
600
|
e = get_responses(stub)
|
425
601
|
expect(e.collect { |r| r }).to eq(@sent_msgs)
|
426
602
|
th.join
|
427
603
|
end
|
604
|
+
|
605
|
+
it 'should raise an error if the status is not ok' do
|
606
|
+
th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @fail, false)
|
607
|
+
stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
|
608
|
+
e = get_responses(stub)
|
609
|
+
expect { e.collect { |r| r } }.to raise_error(GRPC::BadStatus)
|
610
|
+
th.join
|
611
|
+
end
|
612
|
+
|
613
|
+
# TODO: add test for metadata-related ArgumentError in a bidi call once
|
614
|
+
# issue mentioned in https://github.com/grpc/grpc/issues/10526 is fixed
|
615
|
+
|
616
|
+
it 'should send metadata to the server ok' do
|
617
|
+
th = run_bidi_streamer_echo_ping_pong(@sent_msgs, @pass, true,
|
618
|
+
expected_metadata: @metadata)
|
619
|
+
stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
|
620
|
+
e = get_responses(stub)
|
621
|
+
expect(e.collect { |r| r }).to eq(@sent_msgs)
|
622
|
+
th.join
|
623
|
+
end
|
428
624
|
end
|
429
625
|
|
430
626
|
describe 'without a call operation' do
|
431
627
|
def get_responses(stub)
|
432
|
-
e = stub.bidi_streamer(@method, @sent_msgs, noop, noop
|
628
|
+
e = stub.bidi_streamer(@method, @sent_msgs, noop, noop,
|
629
|
+
metadata: @metadata)
|
433
630
|
expect(e).to be_a(Enumerator)
|
434
631
|
e
|
435
632
|
end
|
@@ -443,7 +640,8 @@ describe 'ClientStub' do
|
|
443
640
|
end
|
444
641
|
def get_responses(stub, run_start_call_first: false)
|
445
642
|
@op = stub.bidi_streamer(@method, @sent_msgs, noop, noop,
|
446
|
-
return_op: true
|
643
|
+
return_op: true,
|
644
|
+
metadata: @metadata)
|
447
645
|
expect(@op).to be_a(GRPC::ActiveCall::Operation)
|
448
646
|
@op.start_call if run_start_call_first
|
449
647
|
e = @op.execute
|
@@ -453,27 +651,53 @@ describe 'ClientStub' do
|
|
453
651
|
|
454
652
|
it_behaves_like 'bidi streaming'
|
455
653
|
|
456
|
-
|
457
|
-
|
458
|
-
|
654
|
+
def run_op_view_metadata_test(run_start_call_first)
|
655
|
+
@server_initial_md = { 'sk1' => 'sv1', 'sk2' => 'sv2' }
|
656
|
+
@server_trailing_md = { 'tk1' => 'tv1', 'tk2' => 'tv2' }
|
657
|
+
th = run_bidi_streamer_echo_ping_pong(
|
658
|
+
@sent_msgs, @pass, true,
|
659
|
+
expected_metadata: @metadata,
|
660
|
+
server_initial_md: @server_initial_md,
|
661
|
+
server_trailing_md: @server_trailing_md)
|
459
662
|
stub = GRPC::ClientStub.new(@host, :this_channel_is_insecure)
|
460
|
-
e = get_responses(stub, run_start_call_first:
|
461
|
-
expect(e.collect { |r| r }).to eq(@
|
663
|
+
e = get_responses(stub, run_start_call_first: run_start_call_first)
|
664
|
+
expect(e.collect { |r| r }).to eq(@sent_msgs)
|
462
665
|
th.join
|
463
666
|
end
|
667
|
+
|
668
|
+
it 'can run start_call before executing the call' do
|
669
|
+
run_op_view_metadata_test(true)
|
670
|
+
check_op_view_of_finished_client_call(
|
671
|
+
@op, @server_initial_md, @server_trailing_md) do |responses|
|
672
|
+
responses.each { |r| p r }
|
673
|
+
end
|
674
|
+
end
|
675
|
+
|
676
|
+
it 'doesnt crash when op_view used after call has finished' do
|
677
|
+
run_op_view_metadata_test(false)
|
678
|
+
check_op_view_of_finished_client_call(
|
679
|
+
@op, @server_initial_md, @server_trailing_md) do |responses|
|
680
|
+
responses.each { |r| p r }
|
681
|
+
end
|
682
|
+
end
|
464
683
|
end
|
465
684
|
end
|
466
685
|
|
467
|
-
def run_server_streamer(expected_input, replys, status,
|
468
|
-
|
686
|
+
def run_server_streamer(expected_input, replys, status,
|
687
|
+
expected_metadata: {},
|
688
|
+
server_initial_md: {},
|
689
|
+
server_trailing_md: {})
|
690
|
+
wanted_metadata = expected_metadata.clone
|
469
691
|
wakey_thread do |notifier|
|
470
|
-
c = expect_server_to_be_invoked(
|
692
|
+
c = expect_server_to_be_invoked(
|
693
|
+
notifier, metadata_to_send: server_initial_md)
|
471
694
|
wanted_metadata.each do |k, v|
|
472
695
|
expect(c.metadata[k.to_s]).to eq(v)
|
473
696
|
end
|
474
697
|
expect(c.remote_read).to eq(expected_input)
|
475
698
|
replys.each { |r| c.remote_send(r) }
|
476
|
-
c.send_status(status, status == @pass ? 'OK' : 'NOK', true
|
699
|
+
c.send_status(status, status == @pass ? 'OK' : 'NOK', true,
|
700
|
+
metadata: server_trailing_md)
|
477
701
|
end
|
478
702
|
end
|
479
703
|
|
@@ -487,9 +711,17 @@ describe 'ClientStub' do
|
|
487
711
|
end
|
488
712
|
end
|
489
713
|
|
490
|
-
def run_bidi_streamer_echo_ping_pong(expected_inputs, status, client_starts
|
714
|
+
def run_bidi_streamer_echo_ping_pong(expected_inputs, status, client_starts,
|
715
|
+
expected_metadata: {},
|
716
|
+
server_initial_md: {},
|
717
|
+
server_trailing_md: {})
|
718
|
+
wanted_metadata = expected_metadata.clone
|
491
719
|
wakey_thread do |notifier|
|
492
|
-
c = expect_server_to_be_invoked(
|
720
|
+
c = expect_server_to_be_invoked(
|
721
|
+
notifier, metadata_to_send: server_initial_md)
|
722
|
+
wanted_metadata.each do |k, v|
|
723
|
+
expect(c.metadata[k.to_s]).to eq(v)
|
724
|
+
end
|
493
725
|
expected_inputs.each do |i|
|
494
726
|
if client_starts
|
495
727
|
expect(c.remote_read).to eq(i)
|
@@ -499,33 +731,44 @@ describe 'ClientStub' do
|
|
499
731
|
expect(c.remote_read).to eq(i)
|
500
732
|
end
|
501
733
|
end
|
502
|
-
c.send_status(status, status == @pass ? 'OK' : 'NOK', true
|
734
|
+
c.send_status(status, status == @pass ? 'OK' : 'NOK', true,
|
735
|
+
metadata: server_trailing_md)
|
503
736
|
end
|
504
737
|
end
|
505
738
|
|
506
|
-
def run_client_streamer(expected_inputs, resp, status,
|
507
|
-
|
739
|
+
def run_client_streamer(expected_inputs, resp, status,
|
740
|
+
expected_metadata: {},
|
741
|
+
server_initial_md: {},
|
742
|
+
server_trailing_md: {})
|
743
|
+
wanted_metadata = expected_metadata.clone
|
508
744
|
wakey_thread do |notifier|
|
509
|
-
c = expect_server_to_be_invoked(
|
745
|
+
c = expect_server_to_be_invoked(
|
746
|
+
notifier, metadata_to_send: server_initial_md)
|
510
747
|
expected_inputs.each { |i| expect(c.remote_read).to eq(i) }
|
511
748
|
wanted_metadata.each do |k, v|
|
512
749
|
expect(c.metadata[k.to_s]).to eq(v)
|
513
750
|
end
|
514
751
|
c.remote_send(resp)
|
515
|
-
c.send_status(status, status == @pass ? 'OK' : 'NOK', true
|
752
|
+
c.send_status(status, status == @pass ? 'OK' : 'NOK', true,
|
753
|
+
metadata: server_trailing_md)
|
516
754
|
end
|
517
755
|
end
|
518
756
|
|
519
|
-
def run_request_response(expected_input, resp, status,
|
520
|
-
|
757
|
+
def run_request_response(expected_input, resp, status,
|
758
|
+
expected_metadata: {},
|
759
|
+
server_initial_md: {},
|
760
|
+
server_trailing_md: {})
|
761
|
+
wanted_metadata = expected_metadata.clone
|
521
762
|
wakey_thread do |notifier|
|
522
|
-
c = expect_server_to_be_invoked(
|
763
|
+
c = expect_server_to_be_invoked(
|
764
|
+
notifier, metadata_to_send: server_initial_md)
|
523
765
|
expect(c.remote_read).to eq(expected_input)
|
524
766
|
wanted_metadata.each do |k, v|
|
525
767
|
expect(c.metadata[k.to_s]).to eq(v)
|
526
768
|
end
|
527
769
|
c.remote_send(resp)
|
528
|
-
c.send_status(status, status == @pass ? 'OK' : 'NOK', true
|
770
|
+
c.send_status(status, status == @pass ? 'OK' : 'NOK', true,
|
771
|
+
metadata: server_trailing_md)
|
529
772
|
end
|
530
773
|
end
|
531
774
|
|
@@ -543,13 +786,13 @@ describe 'ClientStub' do
|
|
543
786
|
@server.add_http2_port('0.0.0.0:0', :this_port_is_insecure)
|
544
787
|
end
|
545
788
|
|
546
|
-
def expect_server_to_be_invoked(notifier)
|
789
|
+
def expect_server_to_be_invoked(notifier, metadata_to_send: nil)
|
547
790
|
@server.start
|
548
791
|
notifier.notify(nil)
|
549
792
|
recvd_rpc = @server.request_call
|
550
793
|
recvd_call = recvd_rpc.call
|
551
794
|
recvd_call.metadata = recvd_rpc.metadata
|
552
|
-
recvd_call.run_batch(SEND_INITIAL_METADATA =>
|
795
|
+
recvd_call.run_batch(SEND_INITIAL_METADATA => metadata_to_send)
|
553
796
|
GRPC::ActiveCall.new(recvd_call, noop, noop, INFINITE_FUTURE,
|
554
797
|
metadata_received: true)
|
555
798
|
end
|