# Copyright 2015 gRPC authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'spec_helper' require 'grpc/generic/rpc_desc' require 'grpc/generic/service' # A test message that encodes/decodes using marshal/marshal. class GoodMsg def self.marshal(_o) '' end def self.unmarshal(_o) GoodMsg.new end end # A test message that encodes/decodes using encode/decode. class EncodeDecodeMsg def self.encode(_o) '' end def self.decode(_o) GoodMsg.new end end GenericService = GRPC::GenericService Dsl = GenericService::Dsl describe Dsl do it 'can be included in new classes' do blk = proc { Class.new { include Dsl } } expect(&blk).to_not raise_error end end describe GenericService do context '#underscore' do it 'should convert CamelCase to underscore separated' do expect(GenericService.underscore('AnRPC')).to eq('an_rpc') expect(GenericService.underscore('AMethod')).to eq('a_method') expect(GenericService.underscore('PrintHTML')).to eq('print_html') expect(GenericService.underscore('SeeHTMLBooks')).to eq('see_html_books') expect(GenericService.underscore('SeeHTMLBooks'.freeze)).to eq('see_html_books') end end describe 'including it' do it 'adds a class method, rpc' do c = Class.new do include GenericService end expect(c.methods).to include(:rpc) end it 'adds rpc descs using the added class method, #rpc' do c = Class.new do include GenericService rpc :AnRpc, GoodMsg, GoodMsg end expect(c.rpc_descs).to include(:AnRpc) expect(c.rpc_descs[:AnRpc]).to be_a(GRPC::RpcDesc) end it 'give subclasses access to #rpc_descs' do base = Class.new do include GenericService rpc :AnRpc, GoodMsg, GoodMsg end c = Class.new(base) do end expect(c.rpc_descs).to include(:AnRpc) expect(c.rpc_descs[:AnRpc]).to be_a(GRPC::RpcDesc) end it 'adds a default service name' do c = Class.new do include GenericService end expect(c.service_name).to eq('GenericService') end it 'adds a default service name to subclasses' do base = Class.new do include GenericService end c = Class.new(base) do end expect(c.service_name).to eq('GenericService') end it 'adds the specified service name' do c = Class.new do include GenericService self.service_name = 'test.service.TestService' end expect(c.service_name).to eq('test.service.TestService') end it 'adds the specified service name to subclasses' do base = Class.new do include GenericService self.service_name = 'test.service.TestService' end c = Class.new(base) do end expect(c.service_name).to eq('test.service.TestService') end end describe '#include' do it 'raises if #rpc is missing an arg' do blk = proc do Class.new do include GenericService rpc :AnRpc, GoodMsg end end expect(&blk).to raise_error ArgumentError blk = proc do Class.new do include GenericService rpc :AnRpc end end expect(&blk).to raise_error ArgumentError end describe 'when #rpc args are incorrect' do it 'raises if an arg does not have the marshal or unmarshal methods' do blk = proc do Class.new do include GenericService rpc :AnRpc, GoodMsg, Object end end expect(&blk).to raise_error ArgumentError end it 'raises if a type arg only has the marshal method' do # a bad message type with only a marshal method class OnlyMarshal def marshal(o) o end end blk = proc do Class.new do include GenericService rpc :AnRpc, OnlyMarshal, GoodMsg end end expect(&blk).to raise_error ArgumentError end it 'raises if a type arg only has the unmarshal method' do # a bad message type with only an unmarshal method class OnlyUnmarshal def self.ummarshal(o) o end end blk = proc do Class.new do include GenericService rpc :AnRpc, GoodMsg, OnlyUnmarshal end end expect(&blk).to raise_error ArgumentError end end it 'is ok for services that expect the default {un,}marshal methods' do blk = proc do Class.new do include GenericService rpc :AnRpc, GoodMsg, GoodMsg end end expect(&blk).not_to raise_error end it 'is ok for services that override the default {un,}marshal methods' do blk = proc do Class.new do include GenericService self.marshal_class_method = :encode self.unmarshal_class_method = :decode rpc :AnRpc, EncodeDecodeMsg, EncodeDecodeMsg end end expect(&blk).not_to raise_error end end describe '#rpc_stub_class' do it 'generates a client class that defines any of the rpc methods' do s = Class.new do include GenericService rpc :AnRpc, GoodMsg, GoodMsg rpc :AServerStreamer, GoodMsg, stream(GoodMsg) rpc :AClientStreamer, stream(GoodMsg), GoodMsg rpc :ABidiStreamer, stream(GoodMsg), stream(GoodMsg) end client_class = s.rpc_stub_class expect(client_class.instance_methods).to include(:an_rpc) expect(client_class.instance_methods).to include(:a_server_streamer) expect(client_class.instance_methods).to include(:a_client_streamer) expect(client_class.instance_methods).to include(:a_bidi_streamer) end describe 'the generated instances' do it 'can be instanciated with just a hostname and credentials' do s = Class.new do include GenericService rpc :AnRpc, GoodMsg, GoodMsg rpc :AServerStreamer, GoodMsg, stream(GoodMsg) rpc :AClientStreamer, stream(GoodMsg), GoodMsg rpc :ABidiStreamer, stream(GoodMsg), stream(GoodMsg) end client_class = s.rpc_stub_class blk = proc do client_class.new('fakehostname', :this_channel_is_insecure) end expect(&blk).not_to raise_error end it 'has the methods defined in the service' do s = Class.new do include GenericService rpc :AnRpc, GoodMsg, GoodMsg rpc :AServerStreamer, GoodMsg, stream(GoodMsg) rpc :AClientStreamer, stream(GoodMsg), GoodMsg rpc :ABidiStreamer, stream(GoodMsg), stream(GoodMsg) end client_class = s.rpc_stub_class o = client_class.new('fakehostname', :this_channel_is_insecure) expect(o.methods).to include(:an_rpc) expect(o.methods).to include(:a_bidi_streamer) expect(o.methods).to include(:a_client_streamer) expect(o.methods).to include(:a_bidi_streamer) end end end end