| # 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 |