1# Copyright 2015 gRPC authors. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15require 'spec_helper' 16require 'grpc/generic/rpc_desc' 17require 'grpc/generic/service' 18 19# A test message that encodes/decodes using marshal/marshal. 20class GoodMsg 21 def self.marshal(_o) 22 '' 23 end 24 25 def self.unmarshal(_o) 26 GoodMsg.new 27 end 28end 29 30# A test message that encodes/decodes using encode/decode. 31class EncodeDecodeMsg 32 def self.encode(_o) 33 '' 34 end 35 36 def self.decode(_o) 37 GoodMsg.new 38 end 39end 40 41GenericService = GRPC::GenericService 42Dsl = GenericService::Dsl 43 44describe Dsl do 45 it 'can be included in new classes' do 46 blk = proc { Class.new { include Dsl } } 47 expect(&blk).to_not raise_error 48 end 49end 50 51describe GenericService do 52 context '#underscore' do 53 it 'should convert CamelCase to underscore separated' do 54 expect(GenericService.underscore('AnRPC')).to eq('an_rpc') 55 expect(GenericService.underscore('AMethod')).to eq('a_method') 56 expect(GenericService.underscore('PrintHTML')).to eq('print_html') 57 expect(GenericService.underscore('SeeHTMLBooks')).to eq('see_html_books') 58 59 expect(GenericService.underscore('SeeHTMLBooks'.freeze)).to eq('see_html_books') 60 end 61 end 62 63 describe 'including it' do 64 it 'adds a class method, rpc' do 65 c = Class.new do 66 include GenericService 67 end 68 expect(c.methods).to include(:rpc) 69 end 70 71 it 'adds rpc descs using the added class method, #rpc' do 72 c = Class.new do 73 include GenericService 74 rpc :AnRpc, GoodMsg, GoodMsg 75 end 76 77 expect(c.rpc_descs).to include(:AnRpc) 78 expect(c.rpc_descs[:AnRpc]).to be_a(GRPC::RpcDesc) 79 end 80 81 it 'give subclasses access to #rpc_descs' do 82 base = Class.new do 83 include GenericService 84 rpc :AnRpc, GoodMsg, GoodMsg 85 end 86 c = Class.new(base) do 87 end 88 expect(c.rpc_descs).to include(:AnRpc) 89 expect(c.rpc_descs[:AnRpc]).to be_a(GRPC::RpcDesc) 90 end 91 92 it 'adds a default service name' do 93 c = Class.new do 94 include GenericService 95 end 96 expect(c.service_name).to eq('GenericService') 97 end 98 99 it 'adds a default service name to subclasses' do 100 base = Class.new do 101 include GenericService 102 end 103 c = Class.new(base) do 104 end 105 expect(c.service_name).to eq('GenericService') 106 end 107 108 it 'adds the specified service name' do 109 c = Class.new do 110 include GenericService 111 self.service_name = 'test.service.TestService' 112 end 113 expect(c.service_name).to eq('test.service.TestService') 114 end 115 116 it 'adds the specified service name to subclasses' do 117 base = Class.new do 118 include GenericService 119 self.service_name = 'test.service.TestService' 120 end 121 c = Class.new(base) do 122 end 123 expect(c.service_name).to eq('test.service.TestService') 124 end 125 end 126 127 describe '#include' do 128 it 'raises if #rpc is missing an arg' do 129 blk = proc do 130 Class.new do 131 include GenericService 132 rpc :AnRpc, GoodMsg 133 end 134 end 135 expect(&blk).to raise_error ArgumentError 136 137 blk = proc do 138 Class.new do 139 include GenericService 140 rpc :AnRpc 141 end 142 end 143 expect(&blk).to raise_error ArgumentError 144 end 145 146 describe 'when #rpc args are incorrect' do 147 it 'raises if an arg does not have the marshal or unmarshal methods' do 148 blk = proc do 149 Class.new do 150 include GenericService 151 rpc :AnRpc, GoodMsg, Object 152 end 153 end 154 expect(&blk).to raise_error ArgumentError 155 end 156 157 it 'raises if a type arg only has the marshal method' do 158 # a bad message type with only a marshal method 159 class OnlyMarshal 160 def marshal(o) 161 o 162 end 163 end 164 165 blk = proc do 166 Class.new do 167 include GenericService 168 rpc :AnRpc, OnlyMarshal, GoodMsg 169 end 170 end 171 expect(&blk).to raise_error ArgumentError 172 end 173 174 it 'raises if a type arg only has the unmarshal method' do 175 # a bad message type with only an unmarshal method 176 class OnlyUnmarshal 177 def self.ummarshal(o) 178 o 179 end 180 end 181 blk = proc do 182 Class.new do 183 include GenericService 184 rpc :AnRpc, GoodMsg, OnlyUnmarshal 185 end 186 end 187 expect(&blk).to raise_error ArgumentError 188 end 189 end 190 191 it 'is ok for services that expect the default {un,}marshal methods' do 192 blk = proc do 193 Class.new do 194 include GenericService 195 rpc :AnRpc, GoodMsg, GoodMsg 196 end 197 end 198 expect(&blk).not_to raise_error 199 end 200 201 it 'is ok for services that override the default {un,}marshal methods' do 202 blk = proc do 203 Class.new do 204 include GenericService 205 self.marshal_class_method = :encode 206 self.unmarshal_class_method = :decode 207 rpc :AnRpc, EncodeDecodeMsg, EncodeDecodeMsg 208 end 209 end 210 expect(&blk).not_to raise_error 211 end 212 end 213 214 describe '#rpc_stub_class' do 215 it 'generates a client class that defines any of the rpc methods' do 216 s = Class.new do 217 include GenericService 218 rpc :AnRpc, GoodMsg, GoodMsg 219 rpc :AServerStreamer, GoodMsg, stream(GoodMsg) 220 rpc :AClientStreamer, stream(GoodMsg), GoodMsg 221 rpc :ABidiStreamer, stream(GoodMsg), stream(GoodMsg) 222 end 223 client_class = s.rpc_stub_class 224 expect(client_class.instance_methods).to include(:an_rpc) 225 expect(client_class.instance_methods).to include(:a_server_streamer) 226 expect(client_class.instance_methods).to include(:a_client_streamer) 227 expect(client_class.instance_methods).to include(:a_bidi_streamer) 228 end 229 230 describe 'the generated instances' do 231 it 'can be instanciated with just a hostname and credentials' do 232 s = Class.new do 233 include GenericService 234 rpc :AnRpc, GoodMsg, GoodMsg 235 rpc :AServerStreamer, GoodMsg, stream(GoodMsg) 236 rpc :AClientStreamer, stream(GoodMsg), GoodMsg 237 rpc :ABidiStreamer, stream(GoodMsg), stream(GoodMsg) 238 end 239 client_class = s.rpc_stub_class 240 blk = proc do 241 client_class.new('fakehostname', :this_channel_is_insecure) 242 end 243 expect(&blk).not_to raise_error 244 end 245 246 it 'has the methods defined in the service' do 247 s = Class.new do 248 include GenericService 249 rpc :AnRpc, GoodMsg, GoodMsg 250 rpc :AServerStreamer, GoodMsg, stream(GoodMsg) 251 rpc :AClientStreamer, stream(GoodMsg), GoodMsg 252 rpc :ABidiStreamer, stream(GoodMsg), stream(GoodMsg) 253 end 254 client_class = s.rpc_stub_class 255 o = client_class.new('fakehostname', :this_channel_is_insecure) 256 expect(o.methods).to include(:an_rpc) 257 expect(o.methods).to include(:a_bidi_streamer) 258 expect(o.methods).to include(:a_client_streamer) 259 expect(o.methods).to include(:a_bidi_streamer) 260 end 261 end 262 end 263end 264