grpc 0.5.0
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 +7 -0
- data/.gitignore +15 -0
- data/.rspec +1 -0
- data/.rubocop.yml +10 -0
- data/.rubocop_todo.yml +52 -0
- data/Gemfile +4 -0
- data/README.md +82 -0
- data/Rakefile +54 -0
- data/bin/apis/google/protobuf/empty.rb +44 -0
- data/bin/apis/pubsub_demo.rb +267 -0
- data/bin/apis/tech/pubsub/proto/pubsub.rb +174 -0
- data/bin/apis/tech/pubsub/proto/pubsub_services.rb +103 -0
- data/bin/interop/README.md +8 -0
- data/bin/interop/interop_client.rb +334 -0
- data/bin/interop/interop_server.rb +192 -0
- data/bin/interop/test/cpp/interop/empty.rb +44 -0
- data/bin/interop/test/cpp/interop/messages.rb +89 -0
- data/bin/interop/test/cpp/interop/test.rb +43 -0
- data/bin/interop/test/cpp/interop/test_services.rb +60 -0
- data/bin/math.proto +80 -0
- data/bin/math.rb +61 -0
- data/bin/math_client.rb +147 -0
- data/bin/math_server.rb +190 -0
- data/bin/math_services.rb +56 -0
- data/bin/noproto_client.rb +108 -0
- data/bin/noproto_server.rb +112 -0
- data/ext/grpc/extconf.rb +76 -0
- data/ext/grpc/rb_byte_buffer.c +241 -0
- data/ext/grpc/rb_byte_buffer.h +54 -0
- data/ext/grpc/rb_call.c +569 -0
- data/ext/grpc/rb_call.h +59 -0
- data/ext/grpc/rb_channel.c +264 -0
- data/ext/grpc/rb_channel.h +49 -0
- data/ext/grpc/rb_channel_args.c +154 -0
- data/ext/grpc/rb_channel_args.h +52 -0
- data/ext/grpc/rb_completion_queue.c +185 -0
- data/ext/grpc/rb_completion_queue.h +50 -0
- data/ext/grpc/rb_credentials.c +281 -0
- data/ext/grpc/rb_credentials.h +50 -0
- data/ext/grpc/rb_event.c +361 -0
- data/ext/grpc/rb_event.h +53 -0
- data/ext/grpc/rb_grpc.c +274 -0
- data/ext/grpc/rb_grpc.h +74 -0
- data/ext/grpc/rb_metadata.c +215 -0
- data/ext/grpc/rb_metadata.h +53 -0
- data/ext/grpc/rb_server.c +278 -0
- data/ext/grpc/rb_server.h +50 -0
- data/ext/grpc/rb_server_credentials.c +210 -0
- data/ext/grpc/rb_server_credentials.h +50 -0
- data/grpc.gemspec +41 -0
- data/lib/grpc.rb +39 -0
- data/lib/grpc/core/event.rb +44 -0
- data/lib/grpc/core/time_consts.rb +71 -0
- data/lib/grpc/errors.rb +61 -0
- data/lib/grpc/generic/active_call.rb +536 -0
- data/lib/grpc/generic/bidi_call.rb +221 -0
- data/lib/grpc/generic/client_stub.rb +413 -0
- data/lib/grpc/generic/rpc_desc.rb +150 -0
- data/lib/grpc/generic/rpc_server.rb +404 -0
- data/lib/grpc/generic/service.rb +235 -0
- data/lib/grpc/logconfig.rb +40 -0
- data/lib/grpc/version.rb +33 -0
- data/spec/alloc_spec.rb +44 -0
- data/spec/byte_buffer_spec.rb +67 -0
- data/spec/call_spec.rb +163 -0
- data/spec/channel_spec.rb +181 -0
- data/spec/client_server_spec.rb +372 -0
- data/spec/completion_queue_spec.rb +74 -0
- data/spec/credentials_spec.rb +71 -0
- data/spec/event_spec.rb +53 -0
- data/spec/generic/active_call_spec.rb +373 -0
- data/spec/generic/client_stub_spec.rb +519 -0
- data/spec/generic/rpc_desc_spec.rb +357 -0
- data/spec/generic/rpc_server_pool_spec.rb +139 -0
- data/spec/generic/rpc_server_spec.rb +404 -0
- data/spec/generic/service_spec.rb +342 -0
- data/spec/metadata_spec.rb +64 -0
- data/spec/server_credentials_spec.rb +69 -0
- data/spec/server_spec.rb +212 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/testdata/README +1 -0
- data/spec/testdata/ca.pem +15 -0
- data/spec/testdata/server1.key +16 -0
- data/spec/testdata/server1.pem +16 -0
- data/spec/time_consts_spec.rb +89 -0
- metadata +353 -0
@@ -0,0 +1,181 @@
|
|
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 load_test_certs
|
33
|
+
test_root = File.join(File.dirname(__FILE__), 'testdata')
|
34
|
+
files = ['ca.pem', 'server1.key', 'server1.pem']
|
35
|
+
files.map { |f| File.open(File.join(test_root, f)).read }
|
36
|
+
end
|
37
|
+
|
38
|
+
describe GRPC::Core::Channel do
|
39
|
+
FAKE_HOST = 'localhost:0'
|
40
|
+
|
41
|
+
def create_test_cert
|
42
|
+
GRPC::Core::Credentials.new(load_test_certs[0])
|
43
|
+
end
|
44
|
+
|
45
|
+
before(:each) do
|
46
|
+
@cq = GRPC::Core::CompletionQueue.new
|
47
|
+
end
|
48
|
+
|
49
|
+
shared_examples '#new' do
|
50
|
+
it 'take a host name without channel args' do
|
51
|
+
expect { GRPC::Core::Channel.new('dummy_host', nil) }.not_to raise_error
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'does not take a hash with bad keys as channel args' do
|
55
|
+
blk = construct_with_args(Object.new => 1)
|
56
|
+
expect(&blk).to raise_error TypeError
|
57
|
+
blk = construct_with_args(1 => 1)
|
58
|
+
expect(&blk).to raise_error TypeError
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'does not take a hash with bad values as channel args' do
|
62
|
+
blk = construct_with_args(symbol: Object.new)
|
63
|
+
expect(&blk).to raise_error TypeError
|
64
|
+
blk = construct_with_args('1' => Hash.new)
|
65
|
+
expect(&blk).to raise_error TypeError
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'can take a hash with a symbol key as channel args' do
|
69
|
+
blk = construct_with_args(a_symbol: 1)
|
70
|
+
expect(&blk).to_not raise_error
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'can take a hash with a string key as channel args' do
|
74
|
+
blk = construct_with_args('a_symbol' => 1)
|
75
|
+
expect(&blk).to_not raise_error
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'can take a hash with a string value as channel args' do
|
79
|
+
blk = construct_with_args(a_symbol: '1')
|
80
|
+
expect(&blk).to_not raise_error
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'can take a hash with a symbol value as channel args' do
|
84
|
+
blk = construct_with_args(a_symbol: :another_symbol)
|
85
|
+
expect(&blk).to_not raise_error
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'can take a hash with a numeric value as channel args' do
|
89
|
+
blk = construct_with_args(a_symbol: 1)
|
90
|
+
expect(&blk).to_not raise_error
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'can take a hash with many args as channel args' do
|
94
|
+
args = Hash[127.times.collect { |x| [x.to_s, x] }]
|
95
|
+
blk = construct_with_args(args)
|
96
|
+
expect(&blk).to_not raise_error
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe '#new for secure channels' do
|
101
|
+
def construct_with_args(a)
|
102
|
+
proc { GRPC::Core::Channel.new('dummy_host', a, create_test_cert) }
|
103
|
+
end
|
104
|
+
|
105
|
+
it_behaves_like '#new'
|
106
|
+
end
|
107
|
+
|
108
|
+
describe '#new for insecure channels' do
|
109
|
+
it_behaves_like '#new'
|
110
|
+
|
111
|
+
def construct_with_args(a)
|
112
|
+
proc { GRPC::Core::Channel.new('dummy_host', a) }
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe '#create_call' do
|
117
|
+
it 'creates a call OK' do
|
118
|
+
host = FAKE_HOST
|
119
|
+
ch = GRPC::Core::Channel.new(host, nil)
|
120
|
+
|
121
|
+
deadline = Time.now + 5
|
122
|
+
|
123
|
+
blk = proc do
|
124
|
+
ch.create_call('dummy_method', 'dummy_host', deadline)
|
125
|
+
end
|
126
|
+
expect(&blk).to_not raise_error
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'raises an error if called on a closed channel' do
|
130
|
+
host = FAKE_HOST
|
131
|
+
ch = GRPC::Core::Channel.new(host, nil)
|
132
|
+
ch.close
|
133
|
+
|
134
|
+
deadline = Time.now + 5
|
135
|
+
blk = proc do
|
136
|
+
ch.create_call('dummy_method', 'dummy_host', deadline)
|
137
|
+
end
|
138
|
+
expect(&blk).to raise_error(RuntimeError)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe '#destroy' do
|
143
|
+
it 'destroys a channel ok' do
|
144
|
+
host = FAKE_HOST
|
145
|
+
ch = GRPC::Core::Channel.new(host, nil)
|
146
|
+
blk = proc { ch.destroy }
|
147
|
+
expect(&blk).to_not raise_error
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'can be called more than once without error' do
|
151
|
+
host = FAKE_HOST
|
152
|
+
ch = GRPC::Core::Channel.new(host, nil)
|
153
|
+
blk = proc { ch.destroy }
|
154
|
+
blk.call
|
155
|
+
expect(&blk).to_not raise_error
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe '::SSL_TARGET' do
|
160
|
+
it 'is a symbol' do
|
161
|
+
expect(GRPC::Core::Channel::SSL_TARGET).to be_a(Symbol)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe '#close' do
|
166
|
+
it 'closes a channel ok' do
|
167
|
+
host = FAKE_HOST
|
168
|
+
ch = GRPC::Core::Channel.new(host, nil)
|
169
|
+
blk = proc { ch.close }
|
170
|
+
expect(&blk).to_not raise_error
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'can be called more than once without error' do
|
174
|
+
host = FAKE_HOST
|
175
|
+
ch = GRPC::Core::Channel.new(host, nil)
|
176
|
+
blk = proc { ch.close }
|
177
|
+
blk.call
|
178
|
+
expect(&blk).to_not raise_error
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,372 @@
|
|
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
|
+
require 'spec_helper'
|
32
|
+
|
33
|
+
include GRPC::Core::CompletionType
|
34
|
+
include GRPC::Core
|
35
|
+
|
36
|
+
def load_test_certs
|
37
|
+
test_root = File.join(File.dirname(__FILE__), 'testdata')
|
38
|
+
files = ['ca.pem', 'server1.key', 'server1.pem']
|
39
|
+
files.map { |f| File.open(File.join(test_root, f)).read }
|
40
|
+
end
|
41
|
+
|
42
|
+
shared_context 'setup: tags' do
|
43
|
+
before(:example) do
|
44
|
+
@server_finished_tag = Object.new
|
45
|
+
@client_finished_tag = Object.new
|
46
|
+
@client_metadata_tag = Object.new
|
47
|
+
@server_tag = Object.new
|
48
|
+
@tag = Object.new
|
49
|
+
end
|
50
|
+
|
51
|
+
def deadline
|
52
|
+
Time.now + 2
|
53
|
+
end
|
54
|
+
|
55
|
+
def expect_next_event_on(queue, type, tag)
|
56
|
+
ev = queue.pluck(tag, deadline)
|
57
|
+
if type.nil?
|
58
|
+
expect(ev).to be_nil
|
59
|
+
else
|
60
|
+
expect(ev).to_not be_nil
|
61
|
+
expect(ev.type).to be(type)
|
62
|
+
end
|
63
|
+
ev
|
64
|
+
end
|
65
|
+
|
66
|
+
def server_allows_client_to_proceed
|
67
|
+
@server.request_call(@server_tag)
|
68
|
+
ev = @server_queue.pluck(@server_tag, deadline)
|
69
|
+
expect(ev).not_to be_nil
|
70
|
+
expect(ev.type).to be(SERVER_RPC_NEW)
|
71
|
+
server_call = ev.call
|
72
|
+
server_call.server_accept(@server_queue, @server_finished_tag)
|
73
|
+
server_call.server_end_initial_metadata
|
74
|
+
server_call
|
75
|
+
end
|
76
|
+
|
77
|
+
def server_responds_with(server_call, reply_text)
|
78
|
+
reply = ByteBuffer.new(reply_text)
|
79
|
+
server_call.start_read(@server_tag)
|
80
|
+
ev = @server_queue.pluck(@server_tag, TimeConsts::INFINITE_FUTURE)
|
81
|
+
expect(ev.type).to be(READ)
|
82
|
+
server_call.start_write(reply, @server_tag)
|
83
|
+
ev = @server_queue.pluck(@server_tag, TimeConsts::INFINITE_FUTURE)
|
84
|
+
expect(ev).not_to be_nil
|
85
|
+
expect(ev.type).to be(WRITE_ACCEPTED)
|
86
|
+
end
|
87
|
+
|
88
|
+
def client_sends(call, sent = 'a message')
|
89
|
+
req = ByteBuffer.new(sent)
|
90
|
+
call.start_write(req, @tag)
|
91
|
+
ev = @client_queue.pluck(@tag, TimeConsts::INFINITE_FUTURE)
|
92
|
+
expect(ev).not_to be_nil
|
93
|
+
expect(ev.type).to be(WRITE_ACCEPTED)
|
94
|
+
sent
|
95
|
+
end
|
96
|
+
|
97
|
+
def new_client_call
|
98
|
+
@ch.create_call('/method', 'localhost', deadline)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
shared_examples 'basic GRPC message delivery is OK' do
|
103
|
+
include_context 'setup: tags'
|
104
|
+
|
105
|
+
it 'servers receive requests from clients and start responding' do
|
106
|
+
reply = ByteBuffer.new('the server payload')
|
107
|
+
call = new_client_call
|
108
|
+
call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
|
109
|
+
|
110
|
+
# check the server rpc new was received
|
111
|
+
# @server.request_call(@server_tag)
|
112
|
+
# ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
|
113
|
+
|
114
|
+
# accept the call
|
115
|
+
# server_call = ev.call
|
116
|
+
# server_call.server_accept(@server_queue, @server_finished_tag)
|
117
|
+
# server_call.server_end_initial_metadata
|
118
|
+
server_call = server_allows_client_to_proceed
|
119
|
+
|
120
|
+
# client sends a message
|
121
|
+
msg = client_sends(call)
|
122
|
+
|
123
|
+
# confirm the server can read the inbound message
|
124
|
+
server_call.start_read(@server_tag)
|
125
|
+
ev = expect_next_event_on(@server_queue, READ, @server_tag)
|
126
|
+
expect(ev.result.to_s).to eq(msg)
|
127
|
+
|
128
|
+
# the server response
|
129
|
+
server_call.start_write(reply, @server_tag)
|
130
|
+
expect_next_event_on(@server_queue, WRITE_ACCEPTED, @server_tag)
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'responses written by servers are received by the client' do
|
134
|
+
call = new_client_call
|
135
|
+
call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
|
136
|
+
server_call = server_allows_client_to_proceed
|
137
|
+
client_sends(call)
|
138
|
+
server_responds_with(server_call, 'server_response')
|
139
|
+
|
140
|
+
call.start_read(@tag)
|
141
|
+
ev = expect_next_event_on(@client_queue, READ, @tag)
|
142
|
+
expect(ev.result.to_s).to eq('server_response')
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'servers can ignore a client write and send a status' do
|
146
|
+
call = new_client_call
|
147
|
+
call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
|
148
|
+
|
149
|
+
# check the server rpc new was received
|
150
|
+
@server.request_call(@server_tag)
|
151
|
+
ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
|
152
|
+
expect(ev.tag).to be(@server_tag)
|
153
|
+
|
154
|
+
# accept the call - need to do this to sent status.
|
155
|
+
server_call = ev.call
|
156
|
+
server_call.server_accept(@server_queue, @server_finished_tag)
|
157
|
+
server_call.server_end_initial_metadata
|
158
|
+
server_call.start_write_status(StatusCodes::NOT_FOUND, 'not found',
|
159
|
+
@server_tag)
|
160
|
+
|
161
|
+
# Client sends some data
|
162
|
+
client_sends(call)
|
163
|
+
|
164
|
+
# client gets an empty response for the read, preceeded by some metadata.
|
165
|
+
call.start_read(@tag)
|
166
|
+
expect_next_event_on(@client_queue, CLIENT_METADATA_READ,
|
167
|
+
@client_metadata_tag)
|
168
|
+
ev = expect_next_event_on(@client_queue, READ, @tag)
|
169
|
+
expect(ev.tag).to be(@tag)
|
170
|
+
expect(ev.result.to_s).to eq('')
|
171
|
+
|
172
|
+
# finally, after client sends writes_done, they get the finished.
|
173
|
+
call.writes_done(@tag)
|
174
|
+
expect_next_event_on(@client_queue, FINISH_ACCEPTED, @tag)
|
175
|
+
ev = expect_next_event_on(@client_queue, FINISHED, @client_finished_tag)
|
176
|
+
expect(ev.result.code).to eq(StatusCodes::NOT_FOUND)
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'completes calls by sending status to client and server' do
|
180
|
+
call = new_client_call
|
181
|
+
call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
|
182
|
+
server_call = server_allows_client_to_proceed
|
183
|
+
client_sends(call)
|
184
|
+
server_responds_with(server_call, 'server_response')
|
185
|
+
server_call.start_write_status(10_101, 'status code is 10101', @server_tag)
|
186
|
+
|
187
|
+
# first the client says writes are done
|
188
|
+
call.start_read(@tag)
|
189
|
+
expect_next_event_on(@client_queue, READ, @tag)
|
190
|
+
call.writes_done(@tag)
|
191
|
+
|
192
|
+
# but nothing happens until the server sends a status
|
193
|
+
expect_next_event_on(@server_queue, FINISH_ACCEPTED, @server_tag)
|
194
|
+
ev = expect_next_event_on(@server_queue, FINISHED, @server_finished_tag)
|
195
|
+
expect(ev.result).to be_a(Struct::Status)
|
196
|
+
|
197
|
+
# client gets FINISHED
|
198
|
+
expect_next_event_on(@client_queue, FINISH_ACCEPTED, @tag)
|
199
|
+
ev = expect_next_event_on(@client_queue, FINISHED, @client_finished_tag)
|
200
|
+
expect(ev.result.details).to eq('status code is 10101')
|
201
|
+
expect(ev.result.code).to eq(10_101)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
shared_examples 'GRPC metadata delivery works OK' do
|
206
|
+
include_context 'setup: tags'
|
207
|
+
|
208
|
+
describe 'from client => server' do
|
209
|
+
before(:example) do
|
210
|
+
n = 7 # arbitrary number of metadata
|
211
|
+
diff_keys_fn = proc { |i| [sprintf('k%d', i), sprintf('v%d', i)] }
|
212
|
+
diff_keys = Hash[n.times.collect { |x| diff_keys_fn.call x }]
|
213
|
+
null_vals_fn = proc { |i| [sprintf('k%d', i), sprintf('v\0%d', i)] }
|
214
|
+
null_vals = Hash[n.times.collect { |x| null_vals_fn.call x }]
|
215
|
+
same_keys_fn = proc { |i| [sprintf('k%d', i), [sprintf('v%d', i)] * n] }
|
216
|
+
same_keys = Hash[n.times.collect { |x| same_keys_fn.call x }]
|
217
|
+
symbol_key = { a_key: 'a val' }
|
218
|
+
@valid_metadata = [diff_keys, same_keys, null_vals, symbol_key]
|
219
|
+
@bad_keys = []
|
220
|
+
@bad_keys << { Object.new => 'a value' }
|
221
|
+
@bad_keys << { 1 => 'a value' }
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'raises an exception if a metadata key is invalid' do
|
225
|
+
@bad_keys.each do |md|
|
226
|
+
call = new_client_call
|
227
|
+
expect { call.add_metadata(md) }.to raise_error
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'sends all the metadata pairs when keys and values are valid' do
|
232
|
+
@valid_metadata.each do |md|
|
233
|
+
call = new_client_call
|
234
|
+
call.add_metadata(md)
|
235
|
+
|
236
|
+
# Client begins a call OK
|
237
|
+
call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
|
238
|
+
|
239
|
+
# ... server has all metadata available even though the client did not
|
240
|
+
# send a write
|
241
|
+
@server.request_call(@server_tag)
|
242
|
+
ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
|
243
|
+
replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }]
|
244
|
+
result = ev.result.metadata
|
245
|
+
expect(result.merge(replace_symbols)).to eq(result)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
describe 'from server => client' do
|
251
|
+
before(:example) do
|
252
|
+
n = 7 # arbitrary number of metadata
|
253
|
+
diff_keys_fn = proc { |i| [sprintf('k%d', i), sprintf('v%d', i)] }
|
254
|
+
diff_keys = Hash[n.times.collect { |x| diff_keys_fn.call x }]
|
255
|
+
null_vals_fn = proc { |i| [sprintf('k%d', i), sprintf('v\0%d', i)] }
|
256
|
+
null_vals = Hash[n.times.collect { |x| null_vals_fn.call x }]
|
257
|
+
same_keys_fn = proc { |i| [sprintf('k%d', i), [sprintf('v%d', i)] * n] }
|
258
|
+
same_keys = Hash[n.times.collect { |x| same_keys_fn.call x }]
|
259
|
+
symbol_key = { a_key: 'a val' }
|
260
|
+
@valid_metadata = [diff_keys, same_keys, null_vals, symbol_key]
|
261
|
+
@bad_keys = []
|
262
|
+
@bad_keys << { Object.new => 'a value' }
|
263
|
+
@bad_keys << { 1 => 'a value' }
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'raises an exception if a metadata key is invalid' do
|
267
|
+
@bad_keys.each do |md|
|
268
|
+
call = new_client_call
|
269
|
+
call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
|
270
|
+
|
271
|
+
# server gets the invocation
|
272
|
+
@server.request_call(@server_tag)
|
273
|
+
ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
|
274
|
+
expect { ev.call.add_metadata(md) }.to raise_error
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
it 'sends a hash that contains the status when no metadata is added' do
|
279
|
+
call = new_client_call
|
280
|
+
call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
|
281
|
+
|
282
|
+
# server gets the invocation
|
283
|
+
@server.request_call(@server_tag)
|
284
|
+
ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
|
285
|
+
server_call = ev.call
|
286
|
+
|
287
|
+
# ... server accepts the call without adding metadata
|
288
|
+
server_call.server_accept(@server_queue, @server_finished_tag)
|
289
|
+
server_call.server_end_initial_metadata
|
290
|
+
|
291
|
+
# there is the HTTP status metadata, though there should not be any
|
292
|
+
# TODO: update this with the bug number to be resolved
|
293
|
+
ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ,
|
294
|
+
@client_metadata_tag)
|
295
|
+
expect(ev.result).to eq({})
|
296
|
+
end
|
297
|
+
|
298
|
+
it 'sends all the pairs when keys and values are valid' do
|
299
|
+
@valid_metadata.each do |md|
|
300
|
+
call = new_client_call
|
301
|
+
call.invoke(@client_queue, @client_metadata_tag, @client_finished_tag)
|
302
|
+
|
303
|
+
# server gets the invocation
|
304
|
+
@server.request_call(@server_tag)
|
305
|
+
ev = expect_next_event_on(@server_queue, SERVER_RPC_NEW, @server_tag)
|
306
|
+
server_call = ev.call
|
307
|
+
|
308
|
+
# ... server adds metadata and accepts the call
|
309
|
+
server_call.add_metadata(md)
|
310
|
+
server_call.server_accept(@server_queue, @server_finished_tag)
|
311
|
+
server_call.server_end_initial_metadata
|
312
|
+
|
313
|
+
# Now the client can read the metadata
|
314
|
+
ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ,
|
315
|
+
@client_metadata_tag)
|
316
|
+
replace_symbols = Hash[md.each_pair.collect { |x, y| [x.to_s, y] }]
|
317
|
+
expect(ev.result).to eq(replace_symbols)
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
describe 'the http client/server' do
|
324
|
+
before(:example) do
|
325
|
+
server_host = '0.0.0.0:0'
|
326
|
+
@client_queue = GRPC::Core::CompletionQueue.new
|
327
|
+
@server_queue = GRPC::Core::CompletionQueue.new
|
328
|
+
@server = GRPC::Core::Server.new(@server_queue, nil)
|
329
|
+
server_port = @server.add_http2_port(server_host)
|
330
|
+
@server.start
|
331
|
+
@ch = Channel.new("0.0.0.0:#{server_port}", nil)
|
332
|
+
end
|
333
|
+
|
334
|
+
after(:example) do
|
335
|
+
@ch.close
|
336
|
+
@server.close
|
337
|
+
end
|
338
|
+
|
339
|
+
it_behaves_like 'basic GRPC message delivery is OK' do
|
340
|
+
end
|
341
|
+
|
342
|
+
it_behaves_like 'GRPC metadata delivery works OK' do
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
describe 'the secure http client/server' do
|
347
|
+
before(:example) do
|
348
|
+
certs = load_test_certs
|
349
|
+
server_host = 'localhost:0'
|
350
|
+
@client_queue = GRPC::Core::CompletionQueue.new
|
351
|
+
@server_queue = GRPC::Core::CompletionQueue.new
|
352
|
+
server_creds = GRPC::Core::ServerCredentials.new(nil, certs[1], certs[2])
|
353
|
+
@server = GRPC::Core::Server.new(@server_queue, nil, server_creds)
|
354
|
+
server_port = @server.add_http2_port(server_host, true)
|
355
|
+
@server.start
|
356
|
+
args = { Channel::SSL_TARGET => 'foo.test.google.fr' }
|
357
|
+
@ch = Channel.new("0.0.0.0:#{server_port}", args,
|
358
|
+
GRPC::Core::Credentials.new(certs[0], nil, nil))
|
359
|
+
end
|
360
|
+
|
361
|
+
after(:example) do
|
362
|
+
@server.close
|
363
|
+
end
|
364
|
+
|
365
|
+
# TODO: uncomment after updating the to the new c api
|
366
|
+
# it_behaves_like 'basic GRPC message delivery is OK' do
|
367
|
+
# end
|
368
|
+
|
369
|
+
# TODO: uncomment after updating the to the new c api
|
370
|
+
# it_behaves_like 'GRPC metadata delivery works OK' do
|
371
|
+
# end
|
372
|
+
end
|