OLD | NEW |
(Empty) | |
| 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 'grpc/generic/rpc_desc' |
| 32 require 'grpc/generic/service' |
| 33 |
| 34 # A test message that encodes/decodes using marshal/marshal. |
| 35 class GoodMsg |
| 36 def self.marshal(_o) |
| 37 '' |
| 38 end |
| 39 |
| 40 def self.unmarshal(_o) |
| 41 GoodMsg.new |
| 42 end |
| 43 end |
| 44 |
| 45 # A test message that encodes/decodes using encode/decode. |
| 46 class EncodeDecodeMsg |
| 47 def self.encode(_o) |
| 48 '' |
| 49 end |
| 50 |
| 51 def self.decode(_o) |
| 52 GoodMsg.new |
| 53 end |
| 54 end |
| 55 |
| 56 GenericService = GRPC::GenericService |
| 57 Dsl = GenericService::Dsl |
| 58 |
| 59 describe Dsl do |
| 60 it 'can be included in new classes' do |
| 61 blk = proc { Class.new { include Dsl } } |
| 62 expect(&blk).to_not raise_error |
| 63 end |
| 64 end |
| 65 |
| 66 describe GenericService do |
| 67 context '#underscore' do |
| 68 it 'should convert CamelCase to underscore separated' do |
| 69 expect(GenericService.underscore('AnRPC')).to eq('an_rpc') |
| 70 expect(GenericService.underscore('AMethod')).to eq('a_method') |
| 71 expect(GenericService.underscore('PrintHTML')).to eq('print_html') |
| 72 expect(GenericService.underscore('SeeHTMLBooks')).to eq('see_html_books') |
| 73 end |
| 74 end |
| 75 |
| 76 describe 'including it' do |
| 77 it 'adds a class method, rpc' do |
| 78 c = Class.new do |
| 79 include GenericService |
| 80 end |
| 81 expect(c.methods).to include(:rpc) |
| 82 end |
| 83 |
| 84 it 'adds rpc descs using the added class method, #rpc' do |
| 85 c = Class.new do |
| 86 include GenericService |
| 87 rpc :AnRpc, GoodMsg, GoodMsg |
| 88 end |
| 89 |
| 90 expect(c.rpc_descs).to include(:AnRpc) |
| 91 expect(c.rpc_descs[:AnRpc]).to be_a(GRPC::RpcDesc) |
| 92 end |
| 93 |
| 94 it 'give subclasses access to #rpc_descs' do |
| 95 base = Class.new do |
| 96 include GenericService |
| 97 rpc :AnRpc, GoodMsg, GoodMsg |
| 98 end |
| 99 c = Class.new(base) do |
| 100 end |
| 101 expect(c.rpc_descs).to include(:AnRpc) |
| 102 expect(c.rpc_descs[:AnRpc]).to be_a(GRPC::RpcDesc) |
| 103 end |
| 104 |
| 105 it 'adds a default service name' do |
| 106 c = Class.new do |
| 107 include GenericService |
| 108 end |
| 109 expect(c.service_name).to eq('GenericService') |
| 110 end |
| 111 |
| 112 it 'adds a default service name to subclasses' do |
| 113 base = Class.new do |
| 114 include GenericService |
| 115 end |
| 116 c = Class.new(base) do |
| 117 end |
| 118 expect(c.service_name).to eq('GenericService') |
| 119 end |
| 120 |
| 121 it 'adds the specified service name' do |
| 122 c = Class.new do |
| 123 include GenericService |
| 124 self.service_name = 'test.service.TestService' |
| 125 end |
| 126 expect(c.service_name).to eq('test.service.TestService') |
| 127 end |
| 128 |
| 129 it 'adds the specified service name to subclasses' do |
| 130 base = Class.new do |
| 131 include GenericService |
| 132 self.service_name = 'test.service.TestService' |
| 133 end |
| 134 c = Class.new(base) do |
| 135 end |
| 136 expect(c.service_name).to eq('test.service.TestService') |
| 137 end |
| 138 end |
| 139 |
| 140 describe '#include' do |
| 141 it 'raises if #rpc is missing an arg' do |
| 142 blk = proc do |
| 143 Class.new do |
| 144 include GenericService |
| 145 rpc :AnRpc, GoodMsg |
| 146 end |
| 147 end |
| 148 expect(&blk).to raise_error ArgumentError |
| 149 |
| 150 blk = proc do |
| 151 Class.new do |
| 152 include GenericService |
| 153 rpc :AnRpc |
| 154 end |
| 155 end |
| 156 expect(&blk).to raise_error ArgumentError |
| 157 end |
| 158 |
| 159 describe 'when #rpc args are incorrect' do |
| 160 it 'raises if an arg does not have the marshal or unmarshal methods' do |
| 161 blk = proc do |
| 162 Class.new do |
| 163 include GenericService |
| 164 rpc :AnRpc, GoodMsg, Object |
| 165 end |
| 166 end |
| 167 expect(&blk).to raise_error ArgumentError |
| 168 end |
| 169 |
| 170 it 'raises if a type arg only has the marshal method' do |
| 171 # a bad message type with only a marshal method |
| 172 class OnlyMarshal |
| 173 def marshal(o) |
| 174 o |
| 175 end |
| 176 end |
| 177 |
| 178 blk = proc do |
| 179 Class.new do |
| 180 include GenericService |
| 181 rpc :AnRpc, OnlyMarshal, GoodMsg |
| 182 end |
| 183 end |
| 184 expect(&blk).to raise_error ArgumentError |
| 185 end |
| 186 |
| 187 it 'raises if a type arg only has the unmarshal method' do |
| 188 # a bad message type with only an unmarshal method |
| 189 class OnlyUnmarshal |
| 190 def self.ummarshal(o) |
| 191 o |
| 192 end |
| 193 end |
| 194 blk = proc do |
| 195 Class.new do |
| 196 include GenericService |
| 197 rpc :AnRpc, GoodMsg, OnlyUnmarshal |
| 198 end |
| 199 end |
| 200 expect(&blk).to raise_error ArgumentError |
| 201 end |
| 202 end |
| 203 |
| 204 it 'is ok for services that expect the default {un,}marshal methods' do |
| 205 blk = proc do |
| 206 Class.new do |
| 207 include GenericService |
| 208 rpc :AnRpc, GoodMsg, GoodMsg |
| 209 end |
| 210 end |
| 211 expect(&blk).not_to raise_error |
| 212 end |
| 213 |
| 214 it 'is ok for services that override the default {un,}marshal methods' do |
| 215 blk = proc do |
| 216 Class.new do |
| 217 include GenericService |
| 218 self.marshal_class_method = :encode |
| 219 self.unmarshal_class_method = :decode |
| 220 rpc :AnRpc, EncodeDecodeMsg, EncodeDecodeMsg |
| 221 end |
| 222 end |
| 223 expect(&blk).not_to raise_error |
| 224 end |
| 225 end |
| 226 |
| 227 describe '#rpc_stub_class' do |
| 228 it 'generates a client class that defines any of the rpc methods' do |
| 229 s = Class.new do |
| 230 include GenericService |
| 231 rpc :AnRpc, GoodMsg, GoodMsg |
| 232 rpc :AServerStreamer, GoodMsg, stream(GoodMsg) |
| 233 rpc :AClientStreamer, stream(GoodMsg), GoodMsg |
| 234 rpc :ABidiStreamer, stream(GoodMsg), stream(GoodMsg) |
| 235 end |
| 236 client_class = s.rpc_stub_class |
| 237 expect(client_class.instance_methods).to include(:an_rpc) |
| 238 expect(client_class.instance_methods).to include(:a_server_streamer) |
| 239 expect(client_class.instance_methods).to include(:a_client_streamer) |
| 240 expect(client_class.instance_methods).to include(:a_bidi_streamer) |
| 241 end |
| 242 |
| 243 describe 'the generated instances' do |
| 244 it 'can be instanciated with just a hostname and credentials' do |
| 245 s = Class.new do |
| 246 include GenericService |
| 247 rpc :AnRpc, GoodMsg, GoodMsg |
| 248 rpc :AServerStreamer, GoodMsg, stream(GoodMsg) |
| 249 rpc :AClientStreamer, stream(GoodMsg), GoodMsg |
| 250 rpc :ABidiStreamer, stream(GoodMsg), stream(GoodMsg) |
| 251 end |
| 252 client_class = s.rpc_stub_class |
| 253 blk = proc do |
| 254 client_class.new('fakehostname', :this_channel_is_insecure) |
| 255 end |
| 256 expect(&blk).not_to raise_error |
| 257 end |
| 258 |
| 259 it 'has the methods defined in the service' do |
| 260 s = Class.new do |
| 261 include GenericService |
| 262 rpc :AnRpc, GoodMsg, GoodMsg |
| 263 rpc :AServerStreamer, GoodMsg, stream(GoodMsg) |
| 264 rpc :AClientStreamer, stream(GoodMsg), GoodMsg |
| 265 rpc :ABidiStreamer, stream(GoodMsg), stream(GoodMsg) |
| 266 end |
| 267 client_class = s.rpc_stub_class |
| 268 o = client_class.new('fakehostname', :this_channel_is_insecure) |
| 269 expect(o.methods).to include(:an_rpc) |
| 270 expect(o.methods).to include(:a_bidi_streamer) |
| 271 expect(o.methods).to include(:a_client_streamer) |
| 272 expect(o.methods).to include(:a_bidi_streamer) |
| 273 end |
| 274 end |
| 275 end |
| 276 |
| 277 describe '#assert_rpc_descs_have_methods' do |
| 278 it 'fails if there is no instance method for an rpc descriptor' do |
| 279 c1 = Class.new do |
| 280 include GenericService |
| 281 rpc :AnRpc, GoodMsg, GoodMsg |
| 282 end |
| 283 expect { c1.assert_rpc_descs_have_methods }.to raise_error |
| 284 |
| 285 c2 = Class.new do |
| 286 include GenericService |
| 287 rpc :AnRpc, GoodMsg, GoodMsg |
| 288 rpc :AnotherRpc, GoodMsg, GoodMsg |
| 289 |
| 290 def an_rpc |
| 291 end |
| 292 end |
| 293 expect { c2.assert_rpc_descs_have_methods }.to raise_error |
| 294 end |
| 295 |
| 296 it 'passes if there are corresponding methods for each descriptor' do |
| 297 c = Class.new do |
| 298 include GenericService |
| 299 rpc :AnRpc, GoodMsg, GoodMsg |
| 300 rpc :AServerStreamer, GoodMsg, stream(GoodMsg) |
| 301 rpc :AClientStreamer, stream(GoodMsg), GoodMsg |
| 302 rpc :ABidiStreamer, stream(GoodMsg), stream(GoodMsg) |
| 303 |
| 304 def an_rpc(_req, _call) |
| 305 end |
| 306 |
| 307 def a_server_streamer(_req, _call) |
| 308 end |
| 309 |
| 310 def a_client_streamer(_call) |
| 311 end |
| 312 |
| 313 def a_bidi_streamer(_call) |
| 314 end |
| 315 end |
| 316 expect { c.assert_rpc_descs_have_methods }.to_not raise_error |
| 317 end |
| 318 |
| 319 it 'passes for subclasses of that include GenericService' do |
| 320 base = Class.new do |
| 321 include GenericService |
| 322 rpc :AnRpc, GoodMsg, GoodMsg |
| 323 |
| 324 def an_rpc(_req, _call) |
| 325 end |
| 326 end |
| 327 c = Class.new(base) |
| 328 expect { c.assert_rpc_descs_have_methods }.to_not raise_error |
| 329 expect(c.include?(GenericService)).to be(true) |
| 330 end |
| 331 |
| 332 it 'passes if subclasses define the rpc methods' do |
| 333 base = Class.new do |
| 334 include GenericService |
| 335 rpc :AnRpc, GoodMsg, GoodMsg |
| 336 end |
| 337 c = Class.new(base) do |
| 338 def an_rpc(_req, _call) |
| 339 end |
| 340 end |
| 341 expect { c.assert_rpc_descs_have_methods }.to_not raise_error |
| 342 expect(c.include?(GenericService)).to be(true) |
| 343 end |
| 344 end |
| 345 end |
OLD | NEW |