grpc 1.0.1-x64-mingw32 → 1.1.2-x64-mingw32
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/etc/roots.pem +39 -111
- data/grpc_c.32.ruby +0 -0
- data/grpc_c.64.ruby +0 -0
- data/src/ruby/ext/grpc/extconf.rb +0 -1
- data/src/ruby/ext/grpc/rb_byte_buffer.c +8 -7
- data/src/ruby/ext/grpc/rb_call.c +15 -5
- data/src/ruby/ext/grpc/rb_channel.c +1 -1
- data/src/ruby/ext/grpc/rb_compression_options.c +466 -0
- data/src/ruby/ext/grpc/rb_compression_options.h +44 -0
- data/src/ruby/ext/grpc/rb_grpc.c +3 -1
- data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +198 -190
- data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +306 -294
- data/src/ruby/ext/grpc/rb_server.c +18 -12
- data/src/ruby/lib/grpc/2.0/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/2.1/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/2.2/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/2.3/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/2.4/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/errors.rb +154 -2
- data/src/ruby/lib/grpc/generic/active_call.rb +144 -63
- data/src/ruby/lib/grpc/generic/bidi_call.rb +18 -2
- data/src/ruby/lib/grpc/generic/client_stub.rb +7 -5
- data/src/ruby/lib/grpc/generic/rpc_desc.rb +39 -13
- data/src/ruby/lib/grpc/generic/rpc_server.rb +51 -24
- data/src/ruby/lib/grpc/generic/service.rb +3 -2
- data/src/ruby/lib/grpc/grpc_c.so +0 -0
- data/src/ruby/lib/grpc/version.rb +1 -1
- data/src/ruby/pb/grpc/health/checker.rb +3 -1
- data/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb +7 -0
- data/src/ruby/pb/test/client.rb +307 -7
- data/src/ruby/pb/test/server.rb +26 -1
- data/src/ruby/spec/compression_options_spec.rb +164 -0
- data/src/ruby/spec/error_sanity_spec.rb +64 -0
- data/src/ruby/spec/generic/active_call_spec.rb +290 -12
- data/src/ruby/spec/generic/client_stub_spec.rb +91 -41
- data/src/ruby/spec/generic/rpc_desc_spec.rb +36 -16
- data/src/ruby/spec/generic/rpc_server_pool_spec.rb +22 -28
- data/src/ruby/spec/generic/rpc_server_spec.rb +6 -6
- data/src/ruby/spec/pb/health/checker_spec.rb +27 -19
- data/src/ruby/spec/spec_helper.rb +2 -0
- metadata +18 -8
data/src/ruby/pb/test/server.rb
CHANGED
@@ -129,6 +129,27 @@ def nulls(l)
|
|
129
129
|
[].pack('x' * l).force_encoding('ascii-8bit')
|
130
130
|
end
|
131
131
|
|
132
|
+
def maybe_echo_metadata(_call)
|
133
|
+
|
134
|
+
# these are consistent for all interop tests
|
135
|
+
initial_metadata_key = "x-grpc-test-echo-initial"
|
136
|
+
trailing_metadata_key = "x-grpc-test-echo-trailing-bin"
|
137
|
+
|
138
|
+
if _call.metadata.has_key?(initial_metadata_key)
|
139
|
+
_call.metadata_to_send[initial_metadata_key] = _call.metadata[initial_metadata_key]
|
140
|
+
end
|
141
|
+
if _call.metadata.has_key?(trailing_metadata_key)
|
142
|
+
_call.output_metadata[trailing_metadata_key] = _call.metadata[trailing_metadata_key]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def maybe_echo_status_and_message(req)
|
147
|
+
unless req.response_status.nil?
|
148
|
+
fail GRPC::BadStatus.new_status_exception(
|
149
|
+
req.response_status.code, req.response_status.message)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
132
153
|
# A FullDuplexEnumerator passes requests to a block and yields generated responses
|
133
154
|
class FullDuplexEnumerator
|
134
155
|
include Grpc::Testing
|
@@ -143,6 +164,7 @@ class FullDuplexEnumerator
|
|
143
164
|
begin
|
144
165
|
cls = StreamingOutputCallResponse
|
145
166
|
@requests.each do |req|
|
167
|
+
maybe_echo_status_and_message(req)
|
146
168
|
req.response_parameters.each do |params|
|
147
169
|
resp_size = params.size
|
148
170
|
GRPC.logger.info("read a req, response size is #{resp_size}")
|
@@ -170,6 +192,8 @@ class TestTarget < Grpc::Testing::TestService::Service
|
|
170
192
|
end
|
171
193
|
|
172
194
|
def unary_call(simple_req, _call)
|
195
|
+
maybe_echo_metadata(_call)
|
196
|
+
maybe_echo_status_and_message(simple_req)
|
173
197
|
req_size = simple_req.response_size
|
174
198
|
SimpleResponse.new(payload: Payload.new(type: :COMPRESSABLE,
|
175
199
|
body: nulls(req_size)))
|
@@ -189,7 +213,8 @@ class TestTarget < Grpc::Testing::TestService::Service
|
|
189
213
|
end
|
190
214
|
end
|
191
215
|
|
192
|
-
def full_duplex_call(reqs)
|
216
|
+
def full_duplex_call(reqs, _call)
|
217
|
+
maybe_echo_metadata(_call)
|
193
218
|
# reqs is a lazy Enumerator of the requests sent by the client.
|
194
219
|
FullDuplexEnumerator.new(reqs).each_item
|
195
220
|
end
|
@@ -0,0 +1,164 @@
|
|
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
|
+
describe GRPC::Core::CompressionOptions do
|
33
|
+
# Note these constants should be updated
|
34
|
+
# according to what the core lib provides.
|
35
|
+
|
36
|
+
# Names of supported compression algorithms
|
37
|
+
ALGORITHMS = [:identity, :deflate, :gzip]
|
38
|
+
|
39
|
+
# Names of valid supported compression levels
|
40
|
+
COMPRESS_LEVELS = [:none, :low, :medium, :high]
|
41
|
+
|
42
|
+
it 'implements to_s' do
|
43
|
+
expect { GRPC::Core::CompressionOptions.new.to_s }.to_not raise_error
|
44
|
+
end
|
45
|
+
|
46
|
+
it '#to_channel_arg_hash gives the same result as #to_hash' do
|
47
|
+
options = GRPC::Core::CompressionOptions.new
|
48
|
+
expect(options.to_channel_arg_hash).to eq(options.to_hash)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Test the normal call sequence of creating an instance
|
52
|
+
# and then obtaining the resulting channel-arg hash that
|
53
|
+
# corresponds to the compression settings of the instance
|
54
|
+
describe 'creating, reading, and converting to channel args hash' do
|
55
|
+
it 'works when no optional args were provided' do
|
56
|
+
options = GRPC::Core::CompressionOptions.new
|
57
|
+
|
58
|
+
ALGORITHMS.each do |algorithm|
|
59
|
+
expect(options.algorithm_enabled?(algorithm)).to be true
|
60
|
+
end
|
61
|
+
|
62
|
+
expect(options.disabled_algorithms).to be_empty
|
63
|
+
expect(options.default_algorithm).to be nil
|
64
|
+
expect(options.default_level).to be nil
|
65
|
+
expect(options.to_hash).to be_instance_of(Hash)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'works when disabling multiple algorithms' do
|
69
|
+
options = GRPC::Core::CompressionOptions.new(
|
70
|
+
default_algorithm: :identity,
|
71
|
+
default_level: :none,
|
72
|
+
disabled_algorithms: [:gzip, :deflate]
|
73
|
+
)
|
74
|
+
|
75
|
+
[:gzip, :deflate].each do |algorithm|
|
76
|
+
expect(options.algorithm_enabled?(algorithm)).to be false
|
77
|
+
expect(options.disabled_algorithms.include?(algorithm)).to be true
|
78
|
+
end
|
79
|
+
|
80
|
+
expect(options.default_algorithm).to be(:identity)
|
81
|
+
expect(options.default_level).to be(:none)
|
82
|
+
expect(options.to_hash).to be_instance_of(Hash)
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'works when all optional args have been set' do
|
86
|
+
options = GRPC::Core::CompressionOptions.new(
|
87
|
+
default_algorithm: :gzip,
|
88
|
+
default_level: :low,
|
89
|
+
disabled_algorithms: [:deflate]
|
90
|
+
)
|
91
|
+
|
92
|
+
expect(options.algorithm_enabled?(:deflate)).to be false
|
93
|
+
expect(options.algorithm_enabled?(:gzip)).to be true
|
94
|
+
expect(options.disabled_algorithms).to eq([:deflate])
|
95
|
+
|
96
|
+
expect(options.default_algorithm).to be(:gzip)
|
97
|
+
expect(options.default_level).to be(:low)
|
98
|
+
expect(options.to_hash).to be_instance_of(Hash)
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'doesnt fail when no algorithms are disabled' do
|
102
|
+
options = GRPC::Core::CompressionOptions.new(
|
103
|
+
default_algorithm: :identity,
|
104
|
+
default_level: :high
|
105
|
+
)
|
106
|
+
|
107
|
+
ALGORITHMS.each do |algorithm|
|
108
|
+
expect(options.algorithm_enabled?(algorithm)).to be(true)
|
109
|
+
end
|
110
|
+
|
111
|
+
expect(options.disabled_algorithms).to be_empty
|
112
|
+
expect(options.default_algorithm).to be(:identity)
|
113
|
+
expect(options.default_level).to be(:high)
|
114
|
+
expect(options.to_hash).to be_instance_of(Hash)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe '#new with bad parameters' do
|
119
|
+
it 'should fail with more than one parameter' do
|
120
|
+
blk = proc { GRPC::Core::CompressionOptions.new(:gzip, :none) }
|
121
|
+
expect { blk.call }.to raise_error
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should fail with a non-hash parameter' do
|
125
|
+
blk = proc { GRPC::Core::CompressionOptions.new(:gzip) }
|
126
|
+
expect { blk.call }.to raise_error
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe '#default_algorithm' do
|
131
|
+
it 'returns nil if unset' do
|
132
|
+
options = GRPC::Core::CompressionOptions.new
|
133
|
+
expect(options.default_algorithm).to be(nil)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe '#default_level' do
|
138
|
+
it 'returns nil if unset' do
|
139
|
+
options = GRPC::Core::CompressionOptions.new
|
140
|
+
expect(options.default_level).to be(nil)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe '#disabled_algorithms' do
|
145
|
+
it 'returns an empty list if no algorithms were disabled' do
|
146
|
+
options = GRPC::Core::CompressionOptions.new
|
147
|
+
expect(options.disabled_algorithms).to be_empty
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe '#algorithm_enabled?' do
|
152
|
+
[:none, :any, 'gzip', Object.new, 1].each do |name|
|
153
|
+
it "should fail for parameter ${name} of class #{name.class}" do
|
154
|
+
options = GRPC::Core::CompressionOptions.new(
|
155
|
+
disabled_algorithms: [:gzip])
|
156
|
+
|
157
|
+
blk = proc do
|
158
|
+
options.algorithm_enabled?(name)
|
159
|
+
end
|
160
|
+
expect { blk.call }.to raise_error
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,64 @@
|
|
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
|
+
StatusCodes = GRPC::Core::StatusCodes
|
33
|
+
|
34
|
+
describe StatusCodes do
|
35
|
+
# convert upper snake-case to camel case.
|
36
|
+
# e.g., DEADLINE_EXCEEDED -> DeadlineExceeded
|
37
|
+
def upper_snake_to_camel(name)
|
38
|
+
name.to_s.split('_').map(&:downcase).map(&:capitalize).join('')
|
39
|
+
end
|
40
|
+
|
41
|
+
StatusCodes.constants.each do |status_name|
|
42
|
+
it 'there is a subclass of BadStatus corresponding to StatusCode: ' \
|
43
|
+
"#{status_name} that has code: #{StatusCodes.const_get(status_name)}" do
|
44
|
+
camel_case = upper_snake_to_camel(status_name)
|
45
|
+
error_class = GRPC.const_get(camel_case)
|
46
|
+
# expect the error class to be a subclass of BadStatus
|
47
|
+
expect(error_class < GRPC::BadStatus)
|
48
|
+
|
49
|
+
error_object = error_class.new
|
50
|
+
# check that the code matches the int value of the error's constant
|
51
|
+
status_code = StatusCodes.const_get(status_name)
|
52
|
+
expect(error_object.code).to eq(status_code)
|
53
|
+
|
54
|
+
# check default parameters
|
55
|
+
expect(error_object.details).to eq('unknown cause')
|
56
|
+
expect(error_object.metadata).to eq({})
|
57
|
+
|
58
|
+
# check that the BadStatus factory for creates the correct
|
59
|
+
# exception too
|
60
|
+
from_factory = GRPC::BadStatus.new_status_exception(status_code)
|
61
|
+
expect(from_factory.is_a?(error_class)).to be(true)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -60,8 +60,10 @@ describe GRPC::ActiveCall do
|
|
60
60
|
end
|
61
61
|
|
62
62
|
describe '#multi_req_view' do
|
63
|
-
it 'exposes a fixed subset of the ActiveCall
|
64
|
-
want = %w(cancelled?, deadline, each_remote_read, metadata,
|
63
|
+
it 'exposes a fixed subset of the ActiveCall.methods' do
|
64
|
+
want = %w(cancelled?, deadline, each_remote_read, metadata, \
|
65
|
+
shutdown, peer, peer_cert, send_initial_metadata, \
|
66
|
+
initial_metadata_sent)
|
65
67
|
v = @client_call.multi_req_view
|
66
68
|
want.each do |w|
|
67
69
|
expect(v.methods.include?(w))
|
@@ -70,8 +72,10 @@ describe GRPC::ActiveCall do
|
|
70
72
|
end
|
71
73
|
|
72
74
|
describe '#single_req_view' do
|
73
|
-
it 'exposes a fixed subset of the ActiveCall
|
74
|
-
want = %w(cancelled?, deadline, metadata, shutdown
|
75
|
+
it 'exposes a fixed subset of the ActiveCall.methods' do
|
76
|
+
want = %w(cancelled?, deadline, metadata, shutdown, \
|
77
|
+
send_initial_metadata, metadata_to_send, \
|
78
|
+
merge_metadata_to_send, initial_metadata_sent)
|
75
79
|
v = @client_call.single_req_view
|
76
80
|
want.each do |w|
|
77
81
|
expect(v.methods.include?(w))
|
@@ -133,6 +137,8 @@ describe GRPC::ActiveCall do
|
|
133
137
|
msg = 'message is a string'
|
134
138
|
client_call.write_flag = f
|
135
139
|
client_call.remote_send(msg)
|
140
|
+
# flush the message in case writes are set to buffered
|
141
|
+
call.run_batch(CallOps::SEND_CLOSE_FROM_CLIENT => nil) if f == 1
|
136
142
|
|
137
143
|
# confirm that the message was marshalled
|
138
144
|
recvd_rpc = @server.request_call
|
@@ -149,6 +155,146 @@ describe GRPC::ActiveCall do
|
|
149
155
|
end
|
150
156
|
end
|
151
157
|
|
158
|
+
describe 'sending initial metadata', send_initial_metadata: true do
|
159
|
+
it 'sends metadata before sending a message if it hasnt been sent yet' do
|
160
|
+
call = make_test_call
|
161
|
+
@client_call = ActiveCall.new(
|
162
|
+
call,
|
163
|
+
@pass_through,
|
164
|
+
@pass_through,
|
165
|
+
deadline,
|
166
|
+
started: false)
|
167
|
+
|
168
|
+
metadata = { key: 'dummy_val', other: 'other_val' }
|
169
|
+
expect(@client_call.metadata_sent).to eq(false)
|
170
|
+
@client_call.merge_metadata_to_send(metadata)
|
171
|
+
|
172
|
+
message = 'dummy message'
|
173
|
+
|
174
|
+
expect(call).to(
|
175
|
+
receive(:run_batch)
|
176
|
+
.with(
|
177
|
+
hash_including(
|
178
|
+
CallOps::SEND_INITIAL_METADATA => metadata)).once)
|
179
|
+
|
180
|
+
expect(call).to(
|
181
|
+
receive(:run_batch).with(hash_including(
|
182
|
+
CallOps::SEND_MESSAGE => message)).once)
|
183
|
+
@client_call.remote_send(message)
|
184
|
+
|
185
|
+
expect(@client_call.metadata_sent).to eq(true)
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'doesnt send metadata if it thinks its already been sent' do
|
189
|
+
call = make_test_call
|
190
|
+
|
191
|
+
@client_call = ActiveCall.new(call,
|
192
|
+
@pass_through,
|
193
|
+
@pass_through,
|
194
|
+
deadline)
|
195
|
+
|
196
|
+
expect(@client_call.metadata_sent).to eql(true)
|
197
|
+
expect(call).to(
|
198
|
+
receive(:run_batch).with(hash_including(
|
199
|
+
CallOps::SEND_INITIAL_METADATA)).never)
|
200
|
+
|
201
|
+
@client_call.remote_send('test message')
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'sends metadata if it is explicitly sent and ok to do so' do
|
205
|
+
call = make_test_call
|
206
|
+
|
207
|
+
@client_call = ActiveCall.new(call,
|
208
|
+
@pass_through,
|
209
|
+
@pass_through,
|
210
|
+
deadline,
|
211
|
+
started: false)
|
212
|
+
|
213
|
+
expect(@client_call.metadata_sent).to eql(false)
|
214
|
+
|
215
|
+
metadata = { test_key: 'val' }
|
216
|
+
@client_call.merge_metadata_to_send(metadata)
|
217
|
+
expect(@client_call.metadata_to_send).to eq(metadata)
|
218
|
+
|
219
|
+
expect(call).to(
|
220
|
+
receive(:run_batch).with(hash_including(
|
221
|
+
CallOps::SEND_INITIAL_METADATA =>
|
222
|
+
metadata)).once)
|
223
|
+
@client_call.send_initial_metadata
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'explicit sending does nothing if metadata has already been sent' do
|
227
|
+
call = make_test_call
|
228
|
+
|
229
|
+
@client_call = ActiveCall.new(call,
|
230
|
+
@pass_through,
|
231
|
+
@pass_through,
|
232
|
+
deadline)
|
233
|
+
|
234
|
+
expect(@client_call.metadata_sent).to eql(true)
|
235
|
+
|
236
|
+
blk = proc do
|
237
|
+
@client_call.send_initial_metadata
|
238
|
+
end
|
239
|
+
|
240
|
+
expect { blk.call }.to_not raise_error
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
describe '#merge_metadata_to_send', merge_metadata_to_send: true do
|
245
|
+
it 'adds to existing metadata when there is existing metadata to send' do
|
246
|
+
call = make_test_call
|
247
|
+
starting_metadata = {
|
248
|
+
k1: 'key1_val',
|
249
|
+
k2: 'key2_val',
|
250
|
+
k3: 'key3_val'
|
251
|
+
}
|
252
|
+
|
253
|
+
@client_call = ActiveCall.new(
|
254
|
+
call,
|
255
|
+
@pass_through, @pass_through,
|
256
|
+
deadline,
|
257
|
+
started: false,
|
258
|
+
metadata_to_send: starting_metadata)
|
259
|
+
|
260
|
+
expect(@client_call.metadata_to_send).to eq(starting_metadata)
|
261
|
+
|
262
|
+
@client_call.merge_metadata_to_send(
|
263
|
+
k3: 'key3_new_val',
|
264
|
+
k4: 'key4_val')
|
265
|
+
|
266
|
+
expected_md_to_send = {
|
267
|
+
k1: 'key1_val',
|
268
|
+
k2: 'key2_val',
|
269
|
+
k3: 'key3_new_val',
|
270
|
+
k4: 'key4_val' }
|
271
|
+
|
272
|
+
expect(@client_call.metadata_to_send).to eq(expected_md_to_send)
|
273
|
+
|
274
|
+
@client_call.merge_metadata_to_send(k5: 'key5_val')
|
275
|
+
expected_md_to_send.merge!(k5: 'key5_val')
|
276
|
+
expect(@client_call.metadata_to_send).to eq(expected_md_to_send)
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'fails when initial metadata has already been sent' do
|
280
|
+
call = make_test_call
|
281
|
+
@client_call = ActiveCall.new(
|
282
|
+
call,
|
283
|
+
@pass_through,
|
284
|
+
@pass_through,
|
285
|
+
deadline,
|
286
|
+
started: true)
|
287
|
+
|
288
|
+
expect(@client_call.metadata_sent).to eq(true)
|
289
|
+
|
290
|
+
blk = proc do
|
291
|
+
@client_call.merge_metadata_to_send(k1: 'key1_val')
|
292
|
+
end
|
293
|
+
|
294
|
+
expect { blk.call }.to raise_error
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
152
298
|
describe '#client_invoke' do
|
153
299
|
it 'sends metadata to the server when present' do
|
154
300
|
call = make_test_call
|
@@ -163,7 +309,26 @@ describe GRPC::ActiveCall do
|
|
163
309
|
end
|
164
310
|
end
|
165
311
|
|
166
|
-
describe '#
|
312
|
+
describe '#send_status', send_status: true do
|
313
|
+
it 'works when no metadata or messages have been sent yet' do
|
314
|
+
call = make_test_call
|
315
|
+
ActiveCall.client_invoke(call)
|
316
|
+
|
317
|
+
recvd_rpc = @server.request_call
|
318
|
+
server_call = ActiveCall.new(
|
319
|
+
recvd_rpc.call,
|
320
|
+
@pass_through,
|
321
|
+
@pass_through,
|
322
|
+
deadline,
|
323
|
+
started: false)
|
324
|
+
|
325
|
+
expect(server_call.metadata_sent).to eq(false)
|
326
|
+
blk = proc { server_call.send_status(OK) }
|
327
|
+
expect { blk.call }.to_not raise_error
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
describe '#remote_read', remote_read: true do
|
167
332
|
it 'reads the response sent by a server' do
|
168
333
|
call = make_test_call
|
169
334
|
ActiveCall.client_invoke(call)
|
@@ -205,6 +370,31 @@ describe GRPC::ActiveCall do
|
|
205
370
|
expect(client_call.metadata).to eq(expected)
|
206
371
|
end
|
207
372
|
|
373
|
+
it 'get a status from server when nothing else sent from server' do
|
374
|
+
client_call = make_test_call
|
375
|
+
ActiveCall.client_invoke(client_call)
|
376
|
+
|
377
|
+
recvd_rpc = @server.request_call
|
378
|
+
recvd_call = recvd_rpc.call
|
379
|
+
|
380
|
+
server_call = ActiveCall.new(
|
381
|
+
recvd_call,
|
382
|
+
@pass_through,
|
383
|
+
@pass_through,
|
384
|
+
deadline,
|
385
|
+
started: false)
|
386
|
+
|
387
|
+
server_call.send_status(OK, 'OK')
|
388
|
+
|
389
|
+
# Check that we can receive initial metadata and a status
|
390
|
+
client_call.run_batch(
|
391
|
+
CallOps::RECV_INITIAL_METADATA => nil)
|
392
|
+
batch_result = client_call.run_batch(
|
393
|
+
CallOps::RECV_STATUS_ON_CLIENT => nil)
|
394
|
+
|
395
|
+
expect(batch_result.status.code).to eq(OK)
|
396
|
+
end
|
397
|
+
|
208
398
|
it 'get a nil msg before a status when an OK status is sent' do
|
209
399
|
call = make_test_call
|
210
400
|
ActiveCall.client_invoke(call)
|
@@ -212,7 +402,7 @@ describe GRPC::ActiveCall do
|
|
212
402
|
@pass_through, deadline)
|
213
403
|
msg = 'message is a string'
|
214
404
|
client_call.remote_send(msg)
|
215
|
-
|
405
|
+
call.run_batch(CallOps::SEND_CLOSE_FROM_CLIENT => nil)
|
216
406
|
server_call = expect_server_to_receive(msg)
|
217
407
|
server_call.remote_send('server_response')
|
218
408
|
server_call.send_status(OK, 'OK')
|
@@ -270,7 +460,7 @@ describe GRPC::ActiveCall do
|
|
270
460
|
msg = 'message is a string'
|
271
461
|
reply = 'server_response'
|
272
462
|
client_call.remote_send(msg)
|
273
|
-
|
463
|
+
call.run_batch(CallOps::SEND_CLOSE_FROM_CLIENT => nil)
|
274
464
|
server_call = expect_server_to_receive(msg)
|
275
465
|
e = client_call.each_remote_read
|
276
466
|
n = 3 # arbitrary value > 1
|
@@ -283,7 +473,7 @@ describe GRPC::ActiveCall do
|
|
283
473
|
end
|
284
474
|
end
|
285
475
|
|
286
|
-
describe '#
|
476
|
+
describe '#closing the call from the client' do
|
287
477
|
it 'finishes ok if the server sends a status response' do
|
288
478
|
call = make_test_call
|
289
479
|
ActiveCall.client_invoke(call)
|
@@ -291,7 +481,9 @@ describe GRPC::ActiveCall do
|
|
291
481
|
@pass_through, deadline)
|
292
482
|
msg = 'message is a string'
|
293
483
|
client_call.remote_send(msg)
|
294
|
-
expect
|
484
|
+
expect do
|
485
|
+
call.run_batch(CallOps::SEND_CLOSE_FROM_CLIENT => nil)
|
486
|
+
end.to_not raise_error
|
295
487
|
server_call = expect_server_to_receive(msg)
|
296
488
|
server_call.remote_send('server_response')
|
297
489
|
expect(client_call.remote_read).to eq('server_response')
|
@@ -310,11 +502,13 @@ describe GRPC::ActiveCall do
|
|
310
502
|
server_call.remote_send('server_response')
|
311
503
|
server_call.send_status(OK, 'status code is OK')
|
312
504
|
expect(client_call.remote_read).to eq('server_response')
|
313
|
-
expect
|
505
|
+
expect do
|
506
|
+
call.run_batch(CallOps::SEND_CLOSE_FROM_CLIENT => nil)
|
507
|
+
end.to_not raise_error
|
314
508
|
expect { client_call.finished }.to_not raise_error
|
315
509
|
end
|
316
510
|
|
317
|
-
it 'finishes ok if
|
511
|
+
it 'finishes ok if SEND_CLOSE and RECV_STATUS has been sent' do
|
318
512
|
call = make_test_call
|
319
513
|
ActiveCall.client_invoke(call)
|
320
514
|
client_call = ActiveCall.new(call, @pass_through,
|
@@ -325,7 +519,91 @@ describe GRPC::ActiveCall do
|
|
325
519
|
server_call.remote_send('server_response')
|
326
520
|
server_call.send_status(OK, 'status code is OK')
|
327
521
|
expect(client_call.remote_read).to eq('server_response')
|
328
|
-
expect
|
522
|
+
expect do
|
523
|
+
call.run_batch(
|
524
|
+
CallOps::SEND_CLOSE_FROM_CLIENT => nil,
|
525
|
+
CallOps::RECV_STATUS_ON_CLIENT => nil)
|
526
|
+
end.to_not raise_error
|
527
|
+
end
|
528
|
+
end
|
529
|
+
|
530
|
+
# Test sending of the initial metadata in #run_server_bidi
|
531
|
+
# from the server handler both implicitly and explicitly.
|
532
|
+
describe '#run_server_bidi metadata sending tests', run_server_bidi: true do
|
533
|
+
before(:each) do
|
534
|
+
@requests = ['first message', 'second message']
|
535
|
+
@server_to_client_metadata = { 'test_key' => 'test_val' }
|
536
|
+
@server_status = OK
|
537
|
+
|
538
|
+
@client_call = make_test_call
|
539
|
+
@client_call.run_batch(CallOps::SEND_INITIAL_METADATA => {})
|
540
|
+
|
541
|
+
recvd_rpc = @server.request_call
|
542
|
+
recvd_call = recvd_rpc.call
|
543
|
+
@server_call = ActiveCall.new(
|
544
|
+
recvd_call,
|
545
|
+
@pass_through,
|
546
|
+
@pass_through,
|
547
|
+
deadline,
|
548
|
+
metadata_received: true,
|
549
|
+
started: false,
|
550
|
+
metadata_to_send: @server_to_client_metadata)
|
551
|
+
end
|
552
|
+
|
553
|
+
after(:each) do
|
554
|
+
# Send the requests and send a close so the server can send a status
|
555
|
+
@requests.each do |message|
|
556
|
+
@client_call.run_batch(CallOps::SEND_MESSAGE => message)
|
557
|
+
end
|
558
|
+
@client_call.run_batch(CallOps::SEND_CLOSE_FROM_CLIENT => nil)
|
559
|
+
|
560
|
+
@server_thread.join
|
561
|
+
|
562
|
+
# Expect that initial metadata was sent,
|
563
|
+
# the requests were echoed, and a status was sent
|
564
|
+
batch_result = @client_call.run_batch(
|
565
|
+
CallOps::RECV_INITIAL_METADATA => nil)
|
566
|
+
expect(batch_result.metadata).to eq(@server_to_client_metadata)
|
567
|
+
|
568
|
+
@requests.each do |message|
|
569
|
+
batch_result = @client_call.run_batch(
|
570
|
+
CallOps::RECV_MESSAGE => nil)
|
571
|
+
expect(batch_result.message).to eq(message)
|
572
|
+
end
|
573
|
+
|
574
|
+
batch_result = @client_call.run_batch(
|
575
|
+
CallOps::RECV_STATUS_ON_CLIENT => nil)
|
576
|
+
expect(batch_result.status.code).to eq(@server_status)
|
577
|
+
end
|
578
|
+
|
579
|
+
it 'sends the initial metadata implicitly if not already sent' do
|
580
|
+
# Server handler that doesn't have access to a "call"
|
581
|
+
# It echoes the requests
|
582
|
+
fake_gen_each_reply_with_no_call_param = proc do |msgs|
|
583
|
+
msgs
|
584
|
+
end
|
585
|
+
|
586
|
+
@server_thread = Thread.new do
|
587
|
+
@server_call.run_server_bidi(
|
588
|
+
fake_gen_each_reply_with_no_call_param)
|
589
|
+
@server_call.send_status(@server_status)
|
590
|
+
end
|
591
|
+
end
|
592
|
+
|
593
|
+
it 'sends the metadata when sent explicitly and not already sent' do
|
594
|
+
# Fake server handler that has access to a "call" object and
|
595
|
+
# uses it to explicitly update and send the initial metadata
|
596
|
+
fake_gen_each_reply_with_call_param = proc do |msgs, call_param|
|
597
|
+
call_param.merge_metadata_to_send(@server_to_client_metadata)
|
598
|
+
call_param.send_initial_metadata
|
599
|
+
msgs
|
600
|
+
end
|
601
|
+
|
602
|
+
@server_thread = Thread.new do
|
603
|
+
@server_call.run_server_bidi(
|
604
|
+
fake_gen_each_reply_with_call_param)
|
605
|
+
@server_call.send_status(@server_status)
|
606
|
+
end
|
329
607
|
end
|
330
608
|
end
|
331
609
|
|